- 适配器模式(Adapter Pattern)
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
有时,为复用而设计的工具箱类不能够被复用的原因仅仅是它的接口与专业应用领域所需要的接口不匹配。
以下情况使用适配器模式:
- 你想使用一个已经存在的类,而它的接口不符合你的需求。
- 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见得类协同工作。
- 你想使用一些已经存在的子类、但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
对象适配器:在这种模式下,适配器包含(非继承或实现的方式)一个它所包装的一个类的实例,适配器通过调用包装类对象的方法来完成适配。
类适配器:这种模式用于预期的和已经存在的接口的多个实现和继承,典型情况下,预期的接口被创建为单纯的接口类,尤其对于java这种不支持多继承的语言来说更是这样。
二者区别:
类适配器的重点在于类,是通过构造一个继承Adaptee类来实现适配器的功能;
对象适配器的重点在于对象,是通过在直接包含Adaptee类来实现的,当需要调用特殊功能的时候直接使用Adapter中包含的那个Adaptee对象来调用特殊功能的方法即可。
示例:
- 对象适配器
RowingBoat.java
public interface RowingBoat { void row(); }
FishingBoat.java
public class FishingBoat { public void sail() { System.out.println("The fishing boat is sailing"); } }
FishingBoatAdapter.java
public class FishingBoatAdapter implements RowingBoat { private FishingBoat boat; public FishingBoatAdapter() { boat = new FishingBoat(); } @Override public void row() { boat.sail(); } }
Caption.java
public class Captain { private RowingBoat rowingBoat; public Captain() {} public Captain(RowingBoat rowingBoat) { this.rowingBoat = rowingBoat; } public void setRowingBoat(RowingBoat rowingBoat) { this.rowingBoat = rowingBoat; } public void row() { rowingBoat.row(); } }
App.java
public class App { public static void main(String[] args) { // The captain can only operate rowing boats but with adapter he is able to use fishing boats as well Captain captain = new Captain(new FishingBoatAdapter()); captain.row(); } }
Caption并不操作Rowingboat,而是通过适配器来操作。
如果有另外一种类的船只,可以实现新的适配器,而对于Caption来说也是透明的,调用方式相同。
- 类适配器
EnglishPerson.java
public interface EnglishPerson { void sayEnglish(); }
FrenchPerson.java
public interface FrenchPerson { void sayFrench(); }
Person.java
public class Person { private int id; private String name; /** * person可以现在只能说英语 */ public void sayEnglish(){ System.out.println("Person can say english!"); } /** * 省略setter,getter. */ }
AdapterPerson.java
public class AdapterPerson extends Person implements EnglishPerson, FrenchPerson{ @Override public void sayEnglish() { System.out.println("Person can say English!"); } @Override public void sayFrench() { System.out.println("Person can say French!"); } }
App.java
public class App { public static void main(String[] args) { EnglishPerson engPerson = new AdapterPerson(); engPerson.sayEnglish(); FrenchPerson frcPerson = new AdapterPerson(); frcPerson.sayFrench(); } }
- 桥接模式(Bridge Pattern)
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
以下一些情况使用桥接模式:
- 你不希望在抽象和它的实现之间有一个固定的绑定关系。
- 类的抽象以及它们的实现都应该可以通过生成子类的方法加以补充,这时桥接模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
- 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
- (C++)你想对客户完全隐藏抽象的实现部分,在C++中,类的表示在类接口中是可见的。
- 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
示例:
DrawingAPI.java
public interface DrawingAPI { public void drawCircle(final double x, final double y, final double radius); }
DrawingAPI1.java
public class DrawingAPI1 implements DrawingAPI { public void drawCircle(final double x, final double y, final double radius) { System.out.printf("API1.circle at %f:%f radius %f%n", x, y, radius); } }
DrawingAPI2.java
public class DrawingAPI2 implements DrawingAPI { public void drawCircle(final double x, final double y, final double radius) { System.out.printf("API2.circle at %f:%f radius %f%n", x, y, radius); } }
Shape.java
abstract class Shape { protected DrawingAPI drawingAPI; protected Shape(final DrawingAPI drawingAPI){ this.drawingAPI = drawingAPI; } public abstract void draw(); // low-level public abstract void resizeByPercentage(final double pct); // high-level }
CricleShape.java
public class CircleShape extends Shape { private double x, y, radius; public CircleShape(final double x, final double y, final double radius, final DrawingAPI drawingAPI) { super(drawingAPI); this.x = x; this.y = y; this.radius = radius; } // low-level i.e. Implementation specific public void draw() { drawingAPI.drawCircle(x, y, radius); } // high-level i.e. Abstraction specific public void resizeByPercentage(final double pct) { radius *= (1.0 + pct/100.0); } }
BridgePattern.java
public class BridgePattern { public static void main(final String[] args) { Shape[] shapes = new Shape[] { new CircleShape(1, 2, 3, new DrawingAPI1()), new CircleShape(5, 7, 11, new DrawingAPI2()) }; for (Shape shape : shapes) { shape.resizeByPercentage(2.5); shape.draw(); } } }
架构师成长营