适配器模式是用来做适配的,可以将一个接口转换成另一种接口,使得两个不兼容的接口通过适配器可以一起工作。

适配器模式有两种实现方式:类适配器和对象适配器。

适配器通过继承方式实现,对象适配器通过组合方式实现。

类适配器耦合度较高,目前应用较多的为对象适配器。

适配器模式结构

  1. ITarget:目前业务所期待的接口,即要将被适配类适配成的接口的定义
  2. Adaptee:要被适配的现有组件接口,即不兼容 ITarget 接口的接口
  3. Adapter:转换器,将 被适配类 转换为 适配类

对象适配器:

objectAdapter.PNG

类适配器:

calssAdapter.PNG

图片来自[2]

适配器的实现

类适配器模式实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 类适配器: 基于继承
public interface ITarget {
void f1();
void f2();
void fc();
}

public class Adaptee {
public void fa() { //... }
public void fb() { //... }
public void fc() { //... }
}

public class Adaptor extends Adaptee implements ITarget {
public void f1() {
super.fa();
}

public void f2() {
//...重新实现f2()...
}

// 这里fc()不需要实现,直接继承自Adaptee,这是跟对象适配器最大的不同点
}

对象适配器模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 对象适配器:基于组合
public interface ITarget {
void f1();
void f2();
void fc();
}

public class Adaptee {
public void fa() { //... }
public void fb() { //... }
public void fc() { //... }
}

public class Adaptor implements ITarget {
private Adaptee adaptee;

public Adaptor(Adaptee adaptee) {
this.adaptee = adaptee;
}

public void f1() {
adaptee.fa(); //委托给Adaptee
}

public void f2() {
//...重新实现f2()...
}

public void fc() {
adaptee.fc();
}
}

类适配和对象适配器的选择依据

  • 如果 Adaptee 接口并不多,那两种实现方式都可以。
  • 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都相同,那我们推荐使用类适配器,因为 Adaptor 复用父类 Adaptee 的接口,比起对象适配器的实现方式,Adaptor 的代码量要少一些。
  • 如果Adaptee接口很多,而且Adaptee和ITarget接口定义大部分都不相同,那我们推荐使用对象适配器,因为组合结构相对于继承更加灵活。

应用场景

  1. 封装有缺陷的接口设计
  2. 统一多个类的接口设计(比如 Handler Adapter
  3. 兼容老版本接口
  4. 替换依赖的外部系统
  5. 适配不同格式的数据

参考

[1] 菜鸟教程

[2] C语言中文网