Js中的适配器模式
定义
将一个对象的接口适配成用户所期待的接口。
详细描述
适配器模式就是将不同对象的方法适配成可以对接或者统一调用的方式。它也是包装器的一种。
在生活中也有很多类似的例子,比如有的手机没有3.5耳机插口,所以就需要增加一个转接头来完成适配功能以确保耳机的正常使用,如下图:
在我们平时开发中如果是我们自己定义的方法那么直接修改原方法来方便现在的调用即可,但是有很多时候我们都是使用第三方暴露的api,这个时候就没办法直接对原方法进行修改,所以我们就需要增加一个适配方法来让他们更加丝滑的调用。
代码实例
适配对象
我们在开发中做一些地图渲染的工作,因为某些原因需要使用谷歌地图和百度地图的api同时进行渲染,如果他们暴露出的api一致的话就可以使用统一的调用方法同时调用如:
const googleMap = {
render() {
console.log('开始渲染谷歌地图');
},
};
const baiduMap = {
render() {
console.log('开始渲染百度地图');
},
};
const renderMap = (objData) => {
Object.values(objData).forEach(({ render }) => {
if (typeof render === 'function') render();
});
};
// 开始渲染
renderMap({ googleMap, baiduMap });
// 开始渲染谷歌地图
// 开始渲染百度地图
上述代码因为谷歌和百度地图渲染api一致所以可以同时进行渲染,加入此时我的业务场景还需要使用高德地图来同时渲染(或者谷歌地图暴露的api改变),此时我们不想单独进行判断调用,就可以添加适配器来实现如:
const googleMap = {
render() {
console.log('开始渲染谷歌地图');
},
};
const baiduMap = {
render() {
console.log('开始渲染百度地图');
},
};
const gaodeMap = {
show() {
console.log('开始渲染高德地图');
},
};
// 定义适配对象
const gaodeMapAdapter = {
render() {
gaodeMap.show();
},
};
// api统一调用
const renderMap = (objData) => {
Object.values(objData).forEach(({ render }) => {
if (typeof render === 'function') render();
});
};
// 开始渲染
renderMap({ googleMap, baiduMap, gaodeMapAdapter });
// 开始渲染谷歌地图
// 开始渲染百度地图
// 开始渲染高德地图
上述代码就是定义了适配器对象,使新增加的高德地图的api也能和其他地图api一样融洽的调用。
适配函数
有时候我们在处理数据的时候或者后端新老接口更换,数据结构可能会和之前使用的不一样,然而我们项目中使用了很多以前的老数据结构,这时如果想让项目继续平稳运行要不就把使用老数据结构的地方全部修改但是这可能是一项很大的工程,还可以使用适配器函数来完成数据的转换来确保正常使用,如:
// 老数据结构
const oldData = {
key1: 1111,
key2: 2222,
key3: 3333,
};
// 新数据结构
const newData = [
{
key: 'key4',
value: 4444,
},
{
key: 'key5',
value: 5555,
},
];
// 统一使用函数
const useData = (data) => {
Object.entries(data).forEach(([key, value]) => {
console.log(`使用数据${key} -- ${value}`);
});
};
// 适配器函数
const newDataAdapter = (oldData) => {
return newData.reduce((preData, { key, value }) => {
preData[key] = value;
return preData;
}, oldData);
};
useData(newDataAdapter(oldData));
// 打印
// 使用数据key1 -- 1111
// 使用数据key2 -- 2222
// 使用数据key3 -- 3333
// 使用数据key4 -- 4444
// 使用数据key5 – 5555
上述代码中之前使用的数据结构是对象结构,后来换成了数组结构,这时我们定义了一个适配函数newDataAdapter 值需要在老数据传入的地方调用一下就可以完成新老数据之间的适配,不需要把项目中每个使用的地方都修改一遍。
总结
适配器模式在js中是一种相对简单的模式,但是在我们平时开发和维护项目时使用的地方特别的广泛它可以使我们更加方便的维护和兼容不同的接口调用。它在结构上和一些其他包装模式非常相似如:装饰者模式、代理模式和外观模式等,都是使用一个对象包裹另外一个对象。区别他们的主要是使用意图:
- 适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎样实 现的,也不考虑它们将来可能会如何演化。适配器模式不需要改变已有的接口,就能够 使它们协同作用。
- 装饰者模式和代理模式也不会改变原有对象的接口,但装饰者模式的作用是为了给对象 增加功能。装饰者模式常常形成一条长的装饰链,而适配器模式通常只包装一次。代理 模式是为了控制对对象的访问,通常也只包装一次。
- 外观模式的作用倒是和适配器比较相似,有人把外观模式看成一组对象的适配器,但外 观模式最显著的特点是定义了一个新的接口。