这节,我们来看下另外一种设计模式,属于结构型模式——适配器模式。
适配器,其实很好理解,生活中也随处可见,比如电源适配器、usb 适配器等等,那么适配器模式,也被称为Wrapper 模式。
Wrapper 有“包装器”的意思,适配器模式的定义是:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,解决的痛点便是因接口不兼容导致的类不能正常工作的问题。
如上图所示,A、B 代表已经塑模成型的物体 A 和 B,如果想将这两种物体安装在一起,因为两者的接口是不兼容的,不可能直接安装在一起,这个时候该怎么办?这里,我们可以引入物体 C,物体 C 既要适配 A 的接口,又要适配 B 的接口,经过 C 的无缝“衔接”,便将 A、B 完美结合在了一起。
这里的物体 C 就是我们要说的适配器角色,起到了一定的角色转换的作用。再举个例子,如果想让直流 12v 的笔记本电脑工作在交流 220v 的电源下,就必须要一个电源适配器,该适配器的作用就是将 220v 的 AC 交流转为 12v 的 DC 直流,这就是适配器该干的工作,弥补两者之间的空白——承上启下。
什么时候使用适配器模式,从上面的案例我们也可以看出一点端倪:
适配器模式,根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
适配器模式的通用类图如下:
适配器模式包含的角色如下:
总的一句话,Adapter 就是一个在 Client 中使用 Target 定义的接口来使用 Adaptee 角色(调用 Adaptee 中的方法)的存在。
如上图为使用类适配器实现的适配器模式,具体代码如下:
首先是 Target 接口,也就是我们要适配的目标接口:
package com.isoft;
public interface Target {
public abstract void targetMethod1();
public abstract void targetMethod2();
}
接下来是要被适配的“接口”,即 Adaptee:
package com.isoft;
public class Adaptee {
public void methodA() {
System.out.println("Adaptee methodA invoked.");
}
public void methodB() {
System.out.println("Adaptee methodB invoked.");
}
}
然后是我们的适配器,关键代码如下:
package com.isoft;
public class Adapter extends Adaptee implements Target{
@Override
public void targetMethod1() {
System.out.println("Adapter targetMethod1 inkoked.");
methodA();
}
@Override
public void targetMethod2() {
System.out.println("Adapter targetMethod2 inkoked.");
methodB();
}
}
最后是我们的 Client,在这里就是 Main 类:
package com.isoft;
public class Main {
public static void main(String[] args) {
// 通过Adapter继承Adaptee实现了Adaptee角色的调用
Target target = new Adapter();
target.targetMethod1();
target.targetMethod2();
}
}
执行结果如下:
Adapter targetMethod1 inkoked.
Adaptee methodA invoked.
Adapter targetMethod2 inkoked.
Adaptee methodB invoked.
这里,Client 使用者并不知道 Adaper 适配器是如何工作的,就好比笔记本电脑只需要在 12v 电压下正常工作即可,具体适配器如何适配实现电压转换,笔记本电脑无需关心。
如上图为使用对象适配器实现的适配器模式,具体代码如下:
首先是我们要适配的目标类,这里不是接口了注意:
package com.isoft;
public abstract class Target {
public abstract void targetMethod1();
public abstract void targetMethod2();
}
因为 java 的类不支持多继承,但是在单继承模式下我们可以使用委托来实现方法的调用,修改后的 Adapter 适配器代码如下:
package com.isoft;
public class Adapter extends Target{
private Adaptee adaptee;
public Adapter() {
this.adaptee = new Adaptee();
}
@Override
public void targetMethod1() {
System.out.println("Adapter targetMethod1 inkoked.");
adaptee.methodA();
}
@Override
public void targetMethod2() {
System.out.println("Adapter targetMethod2 inkoked.");
adaptee.methodB();
}
}
Client 调用的时候没有变化,还是如下:
public static void main(String[] args) {
// 通过Adapter使用委托,实现了Adaptee角色的调用
Target target = new Adapter();
target.targetMethod1();
target.targetMethod2();
}
输出结果:
Adapter targetMethod1 inkoked.
Adaptee methodA invoked.
Adapter targetMethod2 inkoked.
Adaptee methodB invoked.
主要优点:
主要缺点:
类适配器与对象适配器的使用场景一致,主要应用于如下场景:
适配器模式,本身属于一种结构型模式,用于在两个对象或者系统之间建立适配链接,使得前后系统衔接更加平滑,适配器模式的实现主要有继承方式的类适配器,和委托方式的对象适配器。