【JS设计模式】水管弯弯——适配器模式

148 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

适配器模式(Adapter): 将一个类(对象)的接口(方法或者属性)转化成另一个接口,以满足用户需求,使类(对象)之间接口的不兼容问题通过适配器得到解决。

适配器,在我们生活中也很常见,我们有时称为转换器,比如说有些电脑没有HDMI接口,想要连接HDMI口的显示器,就需要用到TypeC转HDMI适配器了。

适配器的主要任务是适配两种代码库中不兼容的代码。

异类框架适配器

比如说我们现在有两个框架,一个是我们自己写的A框架,一个是JQuery。

var A = A || {} // 定义A框架
// 通过ID获取元素
A.g = function (id) {
    return document.getElementById(id)
}
// 为元素绑定事件
A.on = function (id, type, fn) {
    // 若传递参数是字符串,则以id处理,否则以元素对象处理
    var dom = typeof id === 'string' ? this.g(id) : id
    // 标准DOM2级添加事件方式
    if (dom.addEventListener) {
        dom.addEventListener(type, fn, false)
    }
    // 兼容IE
    else if (dom.attachEvent) {
        dom.attachEvent('on' + type, fn)
    }
    // 简易添加事件
    else {
        dom[on + 'type'] = fn
    }
}

假设我们现在有个需求,实现一个页面加载事件,加载完成后实现一个点击事件,通过上面的代码我们可以如下所示

// 窗口加载完成事件
A.on(window, 'load', function () {
    // 按钮点击事件
    A.on('mybtn', 'click', function () {
        // code....
    })
})

那么假如我们说A框架不再维护了,我们要改用JQuery,我们要怎么办呢?很明显,逐个逐个用JQuery去替换原来的A框架是不现实的,这个时候我们就可以在A框架和JQ之间加上一层适配器了。

我们只需要像下面这样去重写A框架中的代码即可:

A.g = function (id) {
    return $(id).get(0) // 通过JQ获取JQ对象,然后返回第一个成员
}
A.on = function (id, type, fn) {
    var dom = typeof id === 'string' ? $('#' + id) : $(id)
    dom.on(type, fn)
}

这种重写的复杂度跟两个框架的相似程度有关,血缘相差越远的两个框架,适配器的复杂度越高,因此 尽量引入相似框架。

参数适配器

有时候一个方法会需要有很多个参数,比如下面这样

function M(p1, p2, p3, p4, p5, p6) {
}

我们要记住这些参数的顺序是很折磨人的,而且一般这种情况我们都会选择以 一个参数对象的形式 传入。

/**
 * obj.p1:p1,
 * obj.p2:p2,
 * ...
 * obj.p6:p6
 */
function M(obj) {
}

但是这样又带来一个问题,我们不知道传递的参数是否完整,一些参数可能是必传的,还有一些参数可能是有默认值的,像这种情况,就可以使用参数适配器了。

function M(obj) {
    var _adapter = {
        p1: '我是p1',
        p2: 666,
        p3: {},
        p4: [],
        p5: '我是p5',
        p6: '我是老六'
    }
    for (const key in _adapter) {
        // 进行参数适配
        _adapter[key] = obj[key] || _adapter[key]
    }
    // 下面是代码逻辑
}

上面这种方式就是很多插件参数配置的方法。

数据适配器

上面参数适配器又衍生出来一种数据适配器,它的作用是 把一种格式的数据转换成另一种格式的数据。比如说下面的这个将数组转换成对象的适配器

const arr = ['JavaScript', 'book', '前端编程语言', '8月1日']

// 数据适配器
function arr2ObjAdapter(arr) {
    return {
        name: arr[0],
        type: arr[1],
        title: arr[2],
        time: arr[3]
    }
}

上面这种数据适配器使得我们的数据能够被更加灵活的使用

服务端数据适配

适配器最重要的一点,其实就是 解决了前后端的依赖,前端用的数据不再和后端传递来的数据紧密耦合,这样就算后端因为架构改变了导致传递的数据结构发生了变化,我们只需要写一个适配器即可。

本来我们是请求后端,然后直接使用后端返回来的数据,但是现在我们在中间加上一层数据适配器,让后端传递来的数据经过适配后再为前端所用,这样哪怕后端的数据结构改变了,我们也只需要更改适配器部分即可。