前言
今天我们来看另一个和包装有关的设计模式——适配器模式,和装饰者模式比起来,它更像是一位无名耕耘者,隐身于沟渠之中,干着脏活累活——转换接口。用时下比较火的一个词来比喻这种设计模式的话,那就是女装大佬,这真的是适配器模式最佳类比了,我相信你看完今天的所有内容,一定会明白的
适配器模式
适配器模式将一个类的接口,转换成客户期望的另一个接口,适配器让原本不兼容的接口可以合作无间。
适配器模式采用的设计原则是使用对象组件,以修改的接口包装被适配者,这样的好处是,被适配者的任何子类,都可以搭配适配器使用。
采用适配器模式之后:
要点
- 适配器模式主要是为了在不改变原有接口的基础上,适配客户新的接口
- 当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器模式
- 适配器有两种形式:对象适配器和类适配器。类适配器需要用到多重继承
- 适配器将一个对象包装起来以改变起接口;装饰者将一个对象包装起来以增加新的行为和属性;而外观模式将一群对象“包装”起来以简化其接口
示例代码
从网上搜了一些适配器的示例,但是最后发现还是没有《Head First
设计模式》中的简单,所以最后我还是用了书上的示例。
示例的场景是这样的:假设客户需要一只鸭子,但是我们手里只有火鸡,这时候为了满足客户的需求,我们必须通过适配器将火鸡转换成鸭子。
下面就是整个实现过程:
原始系统接口
首选我们拿到鸭子的接口,其中有两个方法,要给是鸣叫,一个是飞
public interface Duck {
void quack();
void fly();
}
接口实现类
这个是鸭子的实现,这是仅仅是为了后期测试。因为我们现在没有这个实现,所以后面要适配这样一个对象。
public class MallardDuck implements Duck {
@Override
public void quack() {
System.out.println("quack");
}
@Override
public void fly() {
System.out.println("I'm flying");
}
}
被适配对象接口
这个是我们火鸡的原始接口,也就是我们要适配成鸭子的火鸡的基类,也有两个方法,一个是鸣叫,一个是飞。
public interface Turkey {
void gobble();
void fly();
}
火鸡的实现类:
public class WildTurkey implements Turkey {
@Override
public void gobble() {
System.out.println("gobble gobble");
}
@Override
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;
}
@Override
public void quack() {
turkey.gobble();
}
@Override
public void fly() {
for (int i = 0; i < 5; i++) {
turkey.fly();
}
}
}
测试代码
这里我们分别创建了鸭子、火鸡和适配了鸭子的火鸡的示例,演示他们的执行过程:
@Test
public void testDuck() {
MallardDuck duck = new MallardDuck();
WildTurkey turkey = new WildTurkey();
TurkeyAdapter turkeyAdapter = new TurkeyAdapter(turkey);
System.out.println("火鸡:");
turkey.gobble();
turkey.fly();
System.out.println("=============\n绿头鸭:");
duck.quack();
duck.fly();
System.out.println("=============\n火鸡适配的鸭子:");
turkeyAdapter.quack();
turkeyAdapter.fly();
}
从代码中我们可以看到,这里适配了鸭子的火鸡像鸭子一样执行了quack
和fly
操作
运行结果:
总结
从上面的示例中,我们可以很清楚的看到,适配器模式本质上就是类型的转换,除了我们这里的例子,日常生活中还有很多类似的例子,比如电脑显示器VGA
转HDMI
、用电设备插头转换等:
虽然都是类型的包装和转换,但是适配器模式和装饰者模式是有本质区别的,装饰者模式始终是同同一种类型的包装和转换,也就是说所有的包装类于被包装类,本质上都是同一种类型,但是在适配器中,转换和包装的一定是不同的类型,比如火鸡到鸭子。
最后引用一段话来结束今天的内容:
如果它走起来像只鸭子,叫起来像只鸭子,那么它
必定可能是一只鸭子包装了鸭子适配器的火鸡……