优雅的实现接口转换——适配器模式详解
插头转换器我们应该都用过。当我们要使用二插头的电器而身边只有3孔的插座时,一个插头转换器就能解决插头和插座不匹配的问题。如下图所示
插头转换器其实只做了一件事,就是把原本不能使用的三孔插座转换成了能使用的二孔插座。而这也正是我们接下来要讲的适配器模式的本质:把不能被客户端使用的接口转换成了能被客户端使用的接口。
2. 适配器模式详解
2.1 适配器模式的定义
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
2.2 适配器模式的类结构
2.3 适配器模式的实现
- 客户端代码
public class Client {
public void invokeTarget(Target target){
target.request();
}
}
客户端中有个invokeTarget方法,方法接收一个Target接口作参数,我们来看看Target接口定义
- 目标接口
public interface Target {
void request();
}
我现在想让目标类Adaptee的实例能被客户端使用,能成功吗?先来看看Adaptee的类定义
- 目标类
public class Adaptee {
public void request() {
System.out.println("Adaptee!");
}
}
因为Adaptee没有实现Target接口,所以是没办法将它的实例作为参数供客户端方法使用的,那么有什么好办法吗?接下来就是适配器出场的时候了
- 适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.request();
}
}
适配器类实现了Target接口,因而其可以被客户端使用,又由于其内部持有目标类的实例,故而适配器类的工作都被委托给了目标类完成。
- 测试
public class TestCase {
public static void main(String[] args) {
Client client = new Client();
client.invokeTarget(new Adapter(new Adaptee()));
}
}
- 结果
2.4 适配器模式的使用场景
- 需要使用的类库不符合现有系统接口的要求
- 不修改原有系统的情况下作旧系统的升级和改造
2.5 类适配器
上面这种适配器其实叫对象适配器,还有种适配器的变体叫类适配器,关于这两者的区别,也很简单,看适配器类和目标类之间的关系是组合还是继承,组合就是对象适配器,继承就是类适配器。由于组合优于继承,对象适配器相对来说要更常用些。
3. 总结
适配器实现了接口转换,在不修改客户端或者目标类的前提下,使得目标类与客户端的接口兼容,从而可以一起工作,是常用且实用的设计模式。