适配器模式定义:
将一个类的接口,转换成客户期望的另外一个接口。适配器让原本接口不兼容的类可以合作无间。
适配器模式UML图:
对象适配器:
使用对象组合,以修改的接口包装被适配者:这种做法还有额外的优点,那就是,被适配的任何子类,都可以搭配着适配器使用
类适配器:
对象适配器和类适配器的区别就是类适配器继承了Targt和Adaptee,而对象适配器使用组合的方式将请求传递给被适配者。
实例代码:
现在有两个类,一个鸭子,一个火鸡,如下所示:
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'm flying");
}
}
public interface Turkey {
public void gobble();
public void fly();
}
//野生火鸡
public class WildTurkey implements Turkey {
public void gobble() {
System.out.println("Gobble gobble");
}
public void fly() {
System.out.println("I'm flying a short distance");
}
}
现在,假设你却鸭子对象,需要使用火鸡对象来冒充,那么就需要使用到适配器模式了:
//火鸡适配器
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
public void quack() {
turkey.gobble();
}
public void fly() {
for(int i=0; i < 5; i++) {
turkey.fly();
}
}
}
现在我们来测试下:
public class DuckTestDrive {
public static void main(String[] args) {
Duck duck = new MallardDuck();
Turkey turkey = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(turkey);
System.out.println("The Turkey says...");
turkey.gobble();
turkey.fly();
System.out.println("\nThe Duck says...");
testDuck(duck);
System.out.println("\nThe TurkeyAdapter says...");
testDuck(turkeyAdapter);
}
static void testDuck(Duck duck) {
duck.quack();
duck.fly();
}
}
可以看到,我们已经使用火鸡适配器,将一个火鸡冒充成了鸭子,只不过,这个“鸭子”叫的时候是goggle叫,而且由于飞行距离太短,要飞五次才可以达到鸭子的要求。
我们已经了解了设计模式,现在回顾下:
客户使用适配器的过程如下:
1.客户通过目标接口调用适配器的方法对适配器发出请求;
2.适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口;
3.客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。
上述实例代码里面就是如此,客户接口就是Duck,接口调用quack和fly方法,并不清楚它的实现类是哪个,是真的鸭子类或者是被包装的适配器火鸡。
类适配器需要使用多重继承,JAVA语言只支持单继承,所以一般不使用这种适配器,网上很多资料使用类适配器模式的时候,基本都是同时使用了继承target,实现adapter的方式,实际情况下这种使用方式很少时候,在此也不过多赘述。
装饰者模式的优缺点
优点:装饰者模式实现装饰行为的动态增加,不需要修改原有的类,满足了扩展-封闭的原则
缺点:会增加很多实现具体装饰类,代码量多。