设计模式之适配器模式

717 阅读3分钟
原文链接: zhuanlan.zhihu.com
模式动机

适配器模式的作用就是解决两个软件实体间接口不兼容情况.

通常情况下,使用者可以通过目标类的接口访问它所提供的服务。开始时候没有什么问题, 但是一但后续别的接口(如第三方接口)有变动或者后续扩展需求, 此时使用原有接口已经不可以提供服务, 那么我们就需要把现有接口转化为使用者需要的接口.适配器模式就是用来完成这样的转化.

在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adapter),它所包装的对象就是适配者(Adaptee),即被适配的类。

模式定义

适配器模式(Adapter Pattern) :将一个接口转换成使用者希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

模式结构

适配器模式包含如下角色:

  • Target:目标抽象类
  • Adapter:适配器类
  • Adaptee:适配者类
  • Client:客户类
现实世界举例论证

现在世界中的适配器模式使用如: 港式插头转换器, 电源适配器, USB转接口。

需求举例代码实现

我们需要完成一个集成多个第三方地图sdk进行地图渲染功能:

// 谷歌地图,百度地图sdk都有show方法进行调用。

const googleMap = {
    show () {
        // 具体谷歌sdk的实现
        console.log('开始使用谷歌地图渲染')
    }
};

const baiduMap = {
    show () {
        // 具体百度sdk的实现
        console.log('开始使用百度地图渲染')
    }
}

// renderMap方法是提供给使用者来调用
const renderMap = (map) => {
    if (map.show instanceof Function) {
        map.show();
    }
};

renderMap(googleMap);
renderMap(baiduMap);

这个时候产品需要我们集成高德地图sdk,但是高德地图渲染方法不是show方法,而是render方法.

这个时候我们不应该去改动之前的源代码违反开闭原则. 而应该想到适配器模式.

// 谷歌地图,百度地图sdk都有show方法进行调用。

const googleMap = {
    show () {
        // 具体谷歌sdk的实现
        console.log('开始使用谷歌地图渲染')
    }
};

const baiduMap = {
    show () {
        // 具体百度sdk的实现
        console.log('开始使用百度地图渲染')
    }
}

const gaodeMap = {
    render () {
        // 具体高德sdk的实现
        console.log('开始使用高德地图渲染')
    }
}

// 适配器
const gaodeMapAdapater = {
    show () {
        return gaodeMap.render();
    }
}

// renderMap方法是提供给使用者来调用
const renderMap = (map) => {
    if (map.show instanceof Function) {
        map.show();
    }
};

renderMap(googleMap);
renderMap(baiduMap);
renderMap(gaodeMapAdapater);

另外一个例子也是我们常见的场景---数据格式变更, 这个我在开发中经常遇到:

// 这是我们之前上传资源, 后台返回给我们的文件信息.
const responseUploadFile = {
    startTime: '',
    file: {
        size: '100kb',
        type: 'text',
        url: '',
        name: '',
        ...
    },
    id: ''
}

// 如果某天后台突然说因为某些原因后续上传文件返回格式有变动了。如下
const changeResUploadFile = {
    size: '100kb',
    type: 'text',
    url: '',
    name: '',
    startTime: '',
    id: ''
}

// 由于我们之前使用旧格式数据做了很多业务逻辑,这个时候不能其改动,容易导致bug而且需求进行回归测试.
// 采用适配器模式

const responseUploadFileAdapter = (uploadFile) => {
    // 在这里对新的数据进行拼接转化
}
适配器模式分析

优点:

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
  • 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的
  • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
参考资料
design-patterns.readthedocs.io/zh_CN/lates…