适配器的概念可以通过下图进行说明,
生活中最常见的例子就是电压转换插头,通过放置在电源与充电设备之间,能够使得两个原本不能一同使用的物品配合使用。
使用适配器模式的情形可以总结为,
- 现有的类或接口不能满足要求,且不能对现有的类和接口代码进行改动
1.组成角色
适配器模式,根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种。
- 对象适配器模式中,适配器和适配者之间是关联关系
- 类适配器模式中,适配器和适配者之间是继承关系
适配器的组成如下图,
举个例子,如果想让直流 12v 的笔记本电脑工作在交流 220v 的电源下,就必须要一个电源适配器,该适配器的作用就是将 220v 的 AC 交流转为 12v 的 DC 直流。
角色 | 说明 |
---|---|
目标(target) | 该角色定义把其它类转换为何种接口,也就是期望接口,可以是一个抽象类或接口,也可以是具体类。以上文中笔记本电脑为例,即指让笔记本正常工作的直流 12v 电源 |
适配器(Adapter) | 适配器可以调用另一个接口,作为一个转换器,对 Adaptee 和 Target 进行适配,适配器类是适配器模式的核心,通常都是一个具体的类。以上文中笔记本电脑为例,即指电源适配器 |
源角色(被适配 Adaptee ) | 已经存在的、运行良好的类或对象,经过适配器角色的包装,它会成为一个崭新的角色。以上文中笔记本电脑为例,即指 220v 的 AC 电源 |
请求者(Client) | 该角色负责使用 Target 定义的方法进行具体处理,以上文中笔记本电脑为例,即指使用 12v 电源驱动的笔记本电脑。 |
对上方图表内容进行概括,Adapter 就是一个在 Client 中使用 Target 定义的接口来使用 Adaptee 角色(调用 Adaptee 中的方法)的存在。
2.代码实现
类适配器
适配器Adapter与适配者之间使用继承关系,
- 定义Target接口
public Interface Target {
public abstract void targetMethod1();
public abstract void targetMethod2();
}
- 定义适配者
public class Adaptee {
public void methodA() {
System.out.println("Adaptee methodA invoked.");
}
public void methodB() {
System.out.println("Adaptee methodB invoked.");
}
}
- 定义适配器
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使用适配器
public class Main {
public static void main(String[] args) {
// 通过Adapter继承Adaptee实现了Adaptee角色的调用
Target target = new Adapter();
target.targetMethod1();
target.targetMethod2();
}
}
对象适配器
对象适配器使用委托的方式,即适配器中包含适配者的实例对象,
- 定义Target类
注意此处不再是接口,
public abstract class Target {
public abstract void targetMethod1();
public abstract void targetMethod2();
}
- 定义适配者
代码与类适配器中的代码相同 - 定义适配器
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();
}
}
- 使用适配器
public static void main(String[] args) {
// 通过Adapter使用委托,实现了Adaptee角色的调用
Target target = new Adapter();
target.targetMethod1();
target.targetMethod2();
}
3.优缺点
优点:
- 将目标类和适配者解耦,引入适配器实现以Target的方式使用Adaptee,无需修改原结构
- 同一个Adaptee可以在多个不同的系统中复用
- 将两个原本不相关联的类关联在一起
缺点:
- Java和C#等语言不支持多继承,一次最多只能适配一个Adaptee