4

在设计模式中,适配器模式有时候也成为包装样式或者包装,将一个类的接口转换成用户所期待的。一个适配器使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

举一个生活中的栗子,显示器的接口分为VGA接口、DVI接口和HDMI接口,但现在你有一个显示器只支持VGA接口,但是刚巧不巧的的你只有一根DVI接口的数据线,为了能够正常使用显示器,所以你需要一个转接头,让你的显示正常工作,那么这个转接头就是一个很恰当的适配器。

什么是适配器模式

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

在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,是的原本没有任何关系的类可以协同工作。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器,类适配器和接口适配器三种,在适配器模式中,适配器与适配者之间的关联关系。在类适配器模式中适配器与适配者之间是继承关系或者是实现关系。

以上三者在项目中都会经常用到,由于对象适配器是通过关联关系进行耦合的,因此在设计时可以做到比较灵活,而类适配器只能通过复写源角色的方法进行拓展,在实际项目中,对象适配器使用的场景相对较多。

适配器不仅可以转换不同格式的数据,其还有助于采用不同接口的对象之间的合作。它的运作方式如下:

  1. 适配器实现与其中一个现有对象兼容的接口
  2. 现有对象可以使用该接口安全地调用适配器方法
  3. 适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象

适配器模式优缺点

在项目开发过程中减少继承关系这是一个很不错的编程习惯。适配器模式通过封装对象将复杂的转换过程隐藏在其他类中,被封装的对象是甚至完全察觉不到适配器的存在。例如你可以使用一个将所有数据转换为英制单位(如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。

优点
  1. 适配器模式是完全符合单一职责,可以将接口或数据转换代码从程序主要业务逻辑中分离
  2. 客户端代码通过客户端接口与适配器进行交互,你就能在不修改原有客户端代码的情况下在程序中添加新类型的适配器
  3. 提高类的复用性,源角色在原有系统中还可以正常使用
缺点
  1. 代码整体复杂度增加,因为需要新增一些列接口和类。有时直接更改服务类使其与其他代码兼容会更简单
  2. 由于类不支持多继承一次只能适配一个适配者类,而且目标抽象只能为接口,有一定的局限性
  3. 被适配者的方法在Adapter中都会暴漏出来
  4. 对象适配器与类适配器相比,想要置换被适配者类的方法不容易实现

示例

适配器模式的主要角色如下:

  1. 客户端:主要包含当前程序的业务逻辑的类
  2. 客户端接口:描述了其他类与客户端代码合作时必须的协议
  3. 被适配者:包含一些功能的类,客户端与其接口不兼容,因为无法直接调用其功能
  4. 适配器:可以同时与客户端和服务交互的类,适配器接收客户端通过适配器接口发起的调用,并将其转换为适用于封装被适配者对象的调用

上面说适配器模式一共有三种那么就一一的把这三种适配器分别说一下,废话就不多赘述了:

对象适配器模式

类图如下所示:

image

代码示例:

// 目标对象
interface Target {
    request() : void;
}
// 被适配者
class Adaptee {
    constructor() {}
    // 这是源角色,有自己的的业务逻辑
    public specificRequest() : void {}
}
// 适配器
class Adapter implements Target {
    private adaptee : Adaptee;
    constructor(adaptee : Adaptee) {
        this.adaptee = adaptee;
    }
    public request() : void {
        this.adaptee.specificRequest();
    }
}
// 使用
const target : Target = new Adapter(new Adaptee());
target.request();
类适配器模式

对象适配器模式的主要角色如下:

类图如下所示:

image

代码示例:

// 目标对象
interface Target {
    request() : void;
}
// 被适配者
class Adaptee {
    constructor() {}
    // 这是源角色,有自己的的业务逻辑
    public specificRequest() : void {}
}
// 适配器
class Adapter extends Adaptee implements Target {
    constructor() {
        super();
    }
    public request() : void {
        super.specificRequest();
    }
}
接口配器模式

对象适配器模式的主要角色如下:

类图如下所示:

image

代码示例:

interface Adaptee {
    operation1() : void;
    operation2() : void;
}

abstract class AbsAdapter implements Adaptee {
    public operation1() : void {}
    public operation2() : void {}
}

class UseClass extends AbsAdapter {
    public operation1() : void {} // 重写该类
}

总结

适配器模式其目的是为了实现接口的复用,利用已有的代码实现新的功能,使用已经存在的部分子类,可选用随想的适配器,适配子类的父类。基于一些遗留代码的系统常常会使用该模式。在这种情况下, 适配器让遗留代码与现代的类得以相互合作。

适配器可以通过以不同抽象或接口类型实例为参数的构造函数来识别。当适配器的任何方法被调用时, 它会将参数转换为合适的格式, 然后将调用定向到其封装对象中的一个或多个方法。


Aaron
4k 声望6.1k 粉丝

Easy life, happy elimination of bugs.