背景:
欧洲的插座和美式的接口不同,买了美式的电脑,如何在欧洲使用,这就需要一个适配器。
设计:
不改变原来对象的接口,而实现想转换成的类型的接口。
实现:
以鸭子为例,现在有一只火鸡也想接收针对鸭子的请求。
// 鸭子接口
public interface Duck {
public void quack();
public void fly();
}
// 绿头鸭是鸭子的子类
public class MallardDuck implements Duck {
public void quack() {
System.out.println("Quack");
}
public void fly() {
System.out.println("I am flying");
}
}
// 火鸡接口
public interface TurKey {
public void gobble(); // 火鸡不会quack叫
public void fly(); // 火鸡飞得很近
}
// 火鸡的实现
public class WildTurkey implements Turkey {
public void gobble() {
System.out.println("Gobble gobble");
}
public void fly() {
System.out.println("I am flying a short distance");
}
}
// 适配器,把火鸡适配成鸭子
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
public void quack() { // 把火鸡的gobble()叫包装成quack(),这样就可以通过quack()调用火鸡叫了
turkey.gobble();
}
public void fly() { // 多飞几次呗。。
for(int i = 0; i < 5; i++) {
turkey.fly();
}
}
}
// 主类
public class DuckTestDrive {
public static void main(string[] args) {
MallardDuck duck = new MallardDuck(); // 鸭子
WildTurkey turkey = new WildTurkey(); // 火鸡
Duck turkeyAdapter = new TurkeyAdapter(turkey); // 装进鸭子适配器里的火鸡,看起来是鸭子
System.out.println("The Turkey says");
turkey.gooble();
turkey.fly();
System.out.println("\nThe Duck says");
testDuck(duck);
System.out.println("The Turkey says");
testDuck(turkeyAdapter);
}
static void testDuck(Duck duck) { // 和接口绑在一起,而不是和实现绑在一起
duck.quack();
duck.fly();
}
}
总结:
适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
适配器模式充满了良好的OO设计原则:使用对象组合以修改的接口包装被适配器,这种做法还有额外的优点,那就是被适配着的任何子类都可以搭配着适配器使用。
实际上有两种适配器:
- 对象适配器:上述为对象适配器,利用组合方式将请求传送给被适配者。(客户调用鸭子类方法,适配器实现鸭子接口,但它收到方法调用时会委托给火鸡。)
- 类适配器:利用多重继承,继承适配着和目标类。(客户调用鸭子类方法,通过扩展鸭子和火鸡两个类,适配器使得火鸡可以相应对鸭子的请求,火鸡没有鸭子的方法,但是适配器可以将对鸭子方法的调用转接到调用火鸡方法上。)
对象适配器可以适配某个类(鸭子),同时也可以适配该类的任何子类(绿头鸭),其通过组合的方法让代码更有弹性。而类适配器则不需要重新实现整个被适配者,只需要一个类适配器,而不需要一个适配器和被适配者。
装饰者模式和适配器模式比较:
- 装饰者模式:可以让新行为加入到类中而无需修改原有代码,无需进行接口转接。
- 适配器模式:允许客户使用新的库和子集合而无需改变任何代码,会进行接口转接。