引言
设计模式,即Design Patterns,是指在软件设计中,被反复使用的一种代码设计经验。使用设计模式的目的是为了可重用代码,提高代码的可扩展性和可维护性。
显示器使用的是HDMI接口,而电脑用的是Type-c的接口。正常情况下,具备相同接口的设备才能进行连接,因此电脑是无法直接和显示器进行连接的。如果,通过接口转换器(适配器),将HDMI的接口转换成type-c的接口,便可以将电脑和显示器进行连接。
定义
结构型模式
适配器模式:通过接口转换,使得两个不兼容的接口能够在一起工作。
接口在前端可以理解为属性或者方法
模式结构
1. 目标(Target)
当前模块所期待的接口,也就是功能的使用者。
2. 适配者(Adaptee)
被访问和适配的模块提供的接口,也就是功能的提供者。
3. 适配器(Adapter)
桥接模块,消除接口的差异,使两个接口可以在一起工作。
图示:
适配器是在已存系统的情况下,为了 复用现有模块、兼容接口差异 而采用的策略。
特点
优点
- 适配器模式符合开闭原则
- 适配器模式可以复用模块,减少目标模块的变动
- 适配器模式使目标模块和适配者模块解耦
缺点
- 适配器模式要求开发者熟悉适配者和目标的接口,这样开发适配器时才能覆盖所有功能。
- 适配器模式增加了模块的数量,增长了功能的调用链路,增加了系统的复杂度。
所以,前期架构设计时尽量考虑多样的场景,保证其扩展性、稳定性,避免以后因为接口变动而导致开发人员不得已使用适配器模式。
实现
目标模块
const adaptee = new Adaptee();
class Target {
doSomething() {
adaptee.handleTask();
}
}
基础模块
class Adaptee {
handleTask() {
// do something
}
}
说明:目标模块的业务依赖基础模块的某个方法(接口)。之后的某一次版本,基础模块进行了大的升级,提供了增强版的api,为了保证代码的干净程度,并没有做向下兼容的处理。此时便可以使用适配器模式进行兼容。
适配者
class Adaptee {
handleTaskNew() {
// do something
}
}
适配器
const adaptee = new Adaptee();
class Adapter {
handleTask() {
// 数据适配
adaptee.handleTaskNew();
}
}
目标模块
const adapter = new Adapter();
class Target {
doSomething() {
adapter.handleTask();
}
}
举例
用适配器模式模拟电脑和显示器的连接。
分析:电脑(Computer)是目标模块,只接受type-c的接口,显示器(Monitor)是适配者,支持的是HDMI的接口。所以我们必须定义一个转接口(Converter),来转换HDMI接口。
显示器
class Monitor() {
display(type, data) {
if (type === 'HDMI') {
console.log('显示图像', data);
}
}
}
转接口
class Converter() {
monitor;
constructor() {
this.monitor = new Monitor();
}
display(type, data) {
if (type === 'type-c') {
let newData = this.convert(data);
this.monitor.display('HDMI', newData);
}
}
}
电脑
class Computer {
useMonitor() {
let converter = new Converter();
converter.display('type-c', {
...图像数据
});
}
}
电脑启动
let computer = new Computer();
computer.useMonitor();
应用场景
- 工具库升级时,通过适配器模式兼容历史调用
- 组件库变更时,通过适配器模式兼容历史使用