Fork me on GitHub

前端设计模式之【适配器模式】

设计模式之适配器模式。

一、什么是适配器模式?

适配器模式通过把一个类的接口变换成客户端所期待的另一种接口,可以帮我们解决不兼容的问题。

二、适配器模式应用

比如一些公司老项目和新项目的封装机制不同,比如:函数调用名称和参数。我们应该使用适配器模式来抹平两者之间的差异。

十年前的老代码封装的数据请求库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Ajax(type, url, data, success, failed){
// 创建ajax对象
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}

...请求逻辑
}

// 发送get请求
Ajax('get', url地址, post入参, function(data){
// 成功的回调逻辑
}, function(error){
// 失败的回调逻辑
})

现在新封装的数据请求库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default class HttpUtils {
// get 方法
static get(){
...
}

// post 方法
static get(){
...
}
}

// 发起post请求
const postResponse = await HttpUtils.post(URL,params) || {}

// 发起get请求
const getResponse = await HttpUtils.get(URL)

我们要用适配器模式来磨平差异,从而通过老代码的函数名和参数进行请求的调用。

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
// Ajax适配器函数,入参与旧接口保持一致
async function AjaxAdapter(type, url, data, success, failed) {
const type = type.toUpperCase()
let result
try {
// 实际的请求全部由新接口发起
if(type === 'GET') {
result = await HttpUtils.get(url) || {}
} else if(type === 'POST') {
result = await HttpUtils.post(url, data) || {}
}
// 假设请求成功对应的状态码是1
result.statusCode === 1 && success ? success(result) : failed(result.statusCode)
} catch(error) {
// 捕捉网络错误
if(failed){
failed(error.statusCode);
}
}
}

// 用适配器适配旧的Ajax方法
async function Ajax(type, url, data, success, failed) {
await AjaxAdapter(type, url, data, success, failed)
}

三、适配器模式的实践 —— axios

axios 本身就用到了适配器模式,它不仅在浏览器环境下进行使用,而且在 Node 环境下同样可以使用,正式通过这种适配器模式磨平了两种平台的差异。进而能够轻松发起网路请求从而不必在乎底层的实现。

1
2
3
4
5
6
7
8
9
10
11
12
function getDefaultAdapter() {
var adapter;
// 判断当前是否是node环境
if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// 如果是node环境,调用node专属的http适配器
adapter = require('./adapters/http');
} else if (typeof XMLHttpRequest !== 'undefined') {
// 如果是浏览器环境,调用基于xhr的适配器
adapter = require('./adapters/xhr');
}
return adapter;
}

http 适配器:

1
2
3
4
5
module.exports = function httpAdapter(config) {
return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
// 具体逻辑
}
}

xhr 适配器:

1
2
3
4
5
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
// 具体逻辑
}
}
  • 两个适配器的入参都是 config;
  • 两个适配器的出参都是一个 Promise。

PS:详情就读 axios 源码

四、总结

1、有差异,就有适配器

2、统一的接口,统一的入参,统一的出参,统一的规则。