1. 介绍
1.1 定义
适配器模式(Adapter Pattern)又称包装器模式,将一个类(对象)的接口(方法、属性)转化为用户需要的另一个接口,解决类(对象)之间接口不兼容的问题。
旧的接口和使用者不兼容
中间加一个适配器转换接口
1.2 主要功能
主要功能是进行转换匹配,目的是复用已有的功能,而不是来实现新的接口。也就是说,访问者需要的功能应该是已经实现好了的,不需要适配器模式来实现,适配器模式主要是负责把不兼容的接口转换成访问者期望的格式而已。
2. 生活中的例子
电源接口的转接头、Type-C 转 HDMI 等视频转接头。
同声传译,充当两国友人互相交流的中间人
在类似场景中,这些例子有以下特点:
旧有接口格式已经不满足现在的需要。
通过增加适配器来更好地使用旧有接口。
3. 通用实现
3.1 角色
Target:目标抽象类
Adapter:适配器类
Adaptee:适配者类
Client:客户类
3.2 代码
复制
class Socket {
output() {
return '输出220V';
}
}
abstract class Power {
abstract charge(): string;
}
class PowerAdapter extends Power {
constructor(public socket: Socket) {
super();
}
//转换后的接口和转换前不一样
charge() {
return this.socket.output() + ' 经过转换 输出24V';
}
}
let powerAdapter = new PowerAdapter(new Socket());
console.log(powerAdapter.charge());
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
4. 场景
当你想用已有对象的功能,却想修改它的接口时,一般可以考虑一下是不是可以应用适配器模式。
如果你想要使用一个已经存在的对象,但是它的接口不满足需求,那么可以使用适配器模式,把已有的实现转换成你需要的接口。
如果你想创建一个可以复用的对象,而且确定需要和一些不兼容的对象一起工作,这种情况可以使用适配器模式,然后需要什么就适配什么。
4.1 axios
Axios
dispatchRequest
axios源码中采用了process和XMLHttpRequest。 通过宿主环境的特有对象识别当前环境,适配出不同环境下如:客户端浏览器和nodejs的请求方式。
defaults
/adapters 目录中包含如下这些文件
复制
├─adapters
│ http.js
│ README.md
│ xhr.js
1.
2.
3.
4.
xhr
http
适配器的入参都是config,返回的都是promise
复制
//let axios = require('axios');
let url = require('url');
function axios(config: any): any {
let adaptor = getDefaultAdapter();
return adaptor(config);
}
axios({
method: 'GET',
url: 'http://localhost:8080/api/user?id=1'
}).then(function (response: any) {
console.log(response);
}, function (error: any) {
console.log(error);
})
function xhr(config: any) {
return new Promise(function (resolve, reject) {
var request = new XMLHttpRequest();
request.open(config.method, config.url, true);
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
resolve(request.response);
} else {
reject('请求失败');
}
}
}
})
}
function http(config: any) {
let http = require('http');
let urlObject = url.parse(config.url);
return new Promise(function (resolve, reject) {
const options = {
hostname: urlObject.hostname,
port: urlObject.port,
path: urlObject.pathname,
method: config.method
};
var req = http.request(options, function (res: any) {
let chunks: any[] = [];
res.on('data', (chunk: any) => {
chunks.push(chunk);
});
res.on('end', () {
resolve(Buffer.concat(chunks).toString());
});
});
req.on('error', (err: any) => {
reject(err);
});
req.end();
})
}
function getDefaultAdapter(): any {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
adapter = xhr;
} else if (typeof process !== 'undefined') {
adapter = http;
}
return adapter;
}
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.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
server.js
复制
let express = require('express');
let app = express();
app.get('/api/user', (req, res) => {
res.json({ id: req.query.id, name: 'zhufeng' });
});
app.listen(8080);
1.
2.
3.
4.
5.
6.
4.2 jQuery.ajax 适配 Axios
有的使用 jQuery 的老项目使用 $.ajax 来发送请求,现在的新项目一般使用 Axios,那么现在有个老项目的代码中全是 $.ajax,如果逐个修改,无疑工作量巨大而且很容易引发各种乱七八糟 bug,这时可以采用适配器模式来将老的使用形式适配到新的技术栈上: