设计模式-适配器模式


定义

适配器模式(Adapter Pattern)是一种结构性设计模式,它用于将一个类的接口转换成客户端代码期望的另一个接口。这使得原本不兼容的接口能够一起工作。适配器模式通常用于以下情况:

系统需要使用一些已存在的类,但这些类的接口与系统要求的接口不匹配。

系统需要一个可以重用的类,这个类能够与其他类或者系统一起工作,但这个类的接口不符合系统的要求。

适配器模式包括以下几种类型:

对象适配器模式:在这种模式中,适配器类继承自已存在的类,同时实现目标接口。这种方式使用了组合,将一个对象包含在适配器中。

类适配器模式:在这种模式中,适配器类同时继承自已存在的类和实现目标接口。这是使用多重继承的一种方式,通常在静态编程语言中较难实现。

真实世界中的适配器

  • 电源适配器(电脑,手机……)
  • iPhone 手机的 3.5 毫米耳机插口转接头

适配器模式可以解决什么问题

将不兼容的源接口和目标接口进行了协调,使得客户端可以通过目标接口来访问源接口的方法,从而实现了更高的代码灵活性和可重用性。

当系统中某个接口的结构已经无法满足我们现在的业务需求,但又不能改动这个接口,因为可能原来的系统很多功能都依赖于这个接口,改动接口会牵扯到太多文件。因此应对这种场景,我们可以很快地想到可以用适配器模式来解决这个问题。

目的是复用已有的功能,而不是来实现新的接口。也就是说,访问者需要的功能应该是已经实现好了的,不需要适配器模式来实现,适配器模式主要是负责把不兼容的接口转换成访问者期望的格式而已。

在类似场景中,这些例子有以下特点:

  1. 旧有接口格式已经不满足现在的需要;

  2. 通过增加适配器来更好地使用旧有接口;

适配器模式的优缺点

适配器模式的优点:

  1. 已有的功能如果只是接口不兼容,使用适配器适配已有功能,可以使原有逻辑得到更好的复用,有助于避免大规模改写现有代码;
  2. 可扩展性良好,在实现适配器功能的时候,可以调用自己开发的功能,从而方便地扩展系统的功能;
  3. 灵活性好,因为适配器并没有对原有对象的功能有所影响,如果不想使用适配器了,那么直接删掉即可,不会对使用原有对象的代码有影响;

适配器模式的缺点:会让系统变得零乱,明明调用 A,却被适配到了 B,如果系统中这样的情况很多,那么对可阅读性不太友好。如果没必要使用适配器模式的话,可以考虑重构,如果使用的话,可以考虑尽量把文档完善。

代码实现

代码实现一:

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
// 目标接口
class TargetInterface {
request() {
throw new Error("This method should be overridden");
}
}

// 已存在的类,需要适配成目标接口
class Adaptee {
specificRequest() {
return "Adaptee's specific request";
}
}

// 对象适配器
class Adapter extends TargetInterface {
constructor(adaptee) {
super();
this.adaptee = adaptee;
}

request() {
const specific = this.adaptee.specificRequest();
return `Adapter: Transformed ${specific} to a common request`;
}
}

// 使用适配器
const adaptee = new Adaptee();
const adapter = new Adapter(adaptee);

console.log(adapter.request()); // 输出:Adapter: Transformed Adaptee's specific request to a common request

代码实现二:

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
33
34
var googleMap = {
show: function () {
console.log("1");
},
};
// 1.0 版本
// var baiduMap = {
// show: function () {
// console.log("1");
// },
// };

// 2.0 版本,此时 show 方法已经修改为 display
var baiduMap = {
display: function () {
console.log("1");
},
};

// 定义一个适配器,使得 rendMap 调用方式不变
var baiduMapAdapter = {
show: function () {
return baiduMap.display();
},
};

var rendMap = function (map) {
if (map.show instanceof Function) {
map.show();
}
};

rendMap(googleMap);
rendMap(baiduMapAdapter);

代码实现三:

Vue 中的计算属性也是一个适配器模式的实例。
data 中的数据不满足当前的要求,通过计算属性的规则来适配成我们需要的格式,对原有数据并没有改变,只改变了原有数据的表现形式。

References

适配器模式
【JS 设计模式】适配器模式
【IT 老齐 205】设计模式之适配器模式 Adapter
前端 13 种常用设计模式详解合集
很多实战案例:JavaScript 设计模式学习第十三篇-适配器模式
Adapter Pattern – Design Patterns (ep 8)****