适配器模式

适配器在生活中很常见,例如电源适配器、USB串口转接设备等,它们本质上是完成接口转换的功能。在编程领域上,模拟适配器完成接口转换的一种解决方案叫做适配器模式。

在编程中免不了使用别人的API,如果别人提供的API与自己期待的API存在不同的话,可以使用适配器模式把别人提供的API转换成自己的所期待的API,这样一来别人的代码和自己的代码都不需要变动。再者,日后API有所变动的话,只需要更改或替换适配器即可,这样的解决方案符合开闭原则,能够大大提高代码的可维护性。

在适配器模式中有三个角色,target即所期待的使用对象,也是适配器所转换的目标,adapter即适配器,完成接口转换的功能,adaptee即被转换的对象。具体的实现可以通过继承或对象委派来实现,通过继承实现的叫做类适配器,通过对象委派实现的叫做对象适配器,而在JS中往往通过一个函数就可以完成接口的转换功能。

通过继承实现适配器

下面是一个第三方库:

class Painter {
  rect() {
    console.log('画矩形')
  }
  circle() {
    console.log('画圆形')
  }
}
module.exports = Painter

而使用者MyPainter期望的API如下:

interface IMyPainter {
  rect():void;
  circle():void;
  line():void; // 希望有一个画直线的方法
}

由于第三方API没有提供画直线方法,但是又想使用第三方库的画矩形和画圆形的方法,所以写一个适配器来扩展第三方的API完成适配:

class PainterAdapter extends Painter {
   line() {
    console.log('画直线')
   }
}

使用时:

const myPainter = new PainterAdapter()
myPainter.line();
myPainter.rect();

通过对象委派实现适配器

假设使用者MyPainter期望的API如下:

interface IMyPainter {
  drawRect():void;
  drawCircle():void;
}

可以看到同样的功能在第三方库已有实现,但是API不太一样,所以可以使用对象委派的方式适配第三方库

class PainterAdapter {
  constructor() {
    this._painter = new Painter() 
 }
  drawRect(...args) {
    return this._painter.rect(...args)
  }
  drawCircle(...args) {
    return this._painter.circle(...args)
  }
}

使用时

const myPainter = new PainterAdapter()
myPainter.drawRect()
myPainter.drawCircle()

缺省适配器

当你对别人提供的API或数据不太放心的时候,可以使用缺省适配器为别人提供的API或数据设置一个默认值,这样就不怕别人提供的格式不规范导致代码出错。
假设你希望使用的接口还是下面这个

interface IMyPainter {
  rect():void;
  circle():void;
  line():void; // 希望有一个画直线的方法
}

但是你不确定第三方API是否真的提供了相应的方法,你可以写一个缺省适配器使得你使用的时候总有一个默认方法:

class DefaultPainterAdapter extends Painter {
  constructor() {
     super()
     const _defaultImplement = {
       line() { console.log('default draw line') }
     }
     Object.keys(_defaultImplement).forEach((m) => {
        this[m] = this[m] || _defaultImplement[m]
     })
  }
}

接下来就可以放心使用了:

const myPainter = new DefaultPainterAdapter()
myPainter.line()
myPainter.circle()

总结

适配器模式是比较简单也比较常用的设计模式,它的作用是为API的提供者和使用者完成接口转换,但是也增加了代码量。API的提供者与使用者应该尽量保持一致来避免这种额外的开销。

与外观模式的区别

适配器模式关注的是接口转换,使得API的提供者和使用者不必关心对方的实现,体现的是解耦的思想;而外观模式关注的是让API保持统一的接口给API的使用者使用,体现的是封装的思想。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容