设计模式 之 适配器模式

目的

将一个类的接口转换为另一个符合客户期望的接口

达到的目的:

种类

有两种:

  • 对象适配器
  • [ ] 类适配器(嗷~~暂时没有实际场景让自己完全明白嗷?)
  • NOTE: 对象适配器和类适配器使用两种不同的适配方法(分别是组合委托和继承)

举个例子

我这里就拿使用三脚插头充电的苹果手机(港版充电器)来举个例子吧~和图中例子相反

interface IPhoneCharger {
    chargeWith3Footer(): void;
}

// Target
interface PrimaryCharger {
    chargeWith2Footer(): void;
}

// adaptee 
// 苹果手机实现苹果手机充电器接口
class IPhone implements IPhoneCharger {
  chargeWith3Footer() {
      console.log("苹果手机开始充电啦~~~?")
  }
}

// adapter
// 普通充电器适配器 - 实现普通充电器接口 - 使苹果手机等其他充电器可以适配普通2脚充电器进行充电
class PrimaryChargerAdapter implements PrimaryCharger {
    
    private phone: any;
    constructor(phone: any) {
        this.phone = phone;
    }
    chargeWith2Footer(): void {
        if (this.phone.constructor === IPhone) {
          // 适配器在这里适配三脚和二脚充电器接口
          this.phone.chargeWith3Footer();
        }
    }
}

function TestDemo() {
    const iPhone = new IPhone();
    
    // iPhone.chargeWith2Foot(); // will fail
   // 中国大陆一般都是2插口插座~需要使用2脚充电器充电 chargeWith2Footer(),
   // 但是苹果手机是三脚充电器不支持~~
    
    // 通过充电器适配器,实现了chargeWith2Footer(),符合客户期望的接口~~~
    const adaptedIPhone = new PrimaryChargerAdapter(iPhone);
    adaptedIPhone.chargeWith2Footer(); // 完美~~
}

TestDemo();

对号入座

Java中的适配器

客户使用适配器的过程解析:

  1. 客户通过目标接口调用适配器的方法对适配器发起请求
  2. 适配器使用被适配者接口把请求换成被适配者的一个或多个调用接口
  3. 客户收到调用的结果,但未察觉一切是适配器的转换作用。
//  改造成ts形式~~
class OldClassAdapter implements NewInterface {
  private OldClass ref;
  constructor(OldClass oc) {
    this.ref = oc;
  }
  public NewMethod(): void {
     this.ref.OldMethod();
  }
}
  • 或许结合这一段代码就可以更加理解适配器模式使用的场景

思考 ?

  • 我所认为的适配器模式应该尽量不去修改被适配者。
  • 真正想做的是应该是接口的转换。

优点

对象适配器模式优点:
(1) 一个对象适配器可以把多个不同的适配者适配到同一个目标;
(2) 将目标类和被适配者类解耦,通过引入一个适配器类来重用现有的被适配者类,无须修改原有结构。

缺点

过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现.

适配器模式 VS 外观模式

先看下面这段熟悉的代码~~ 摘自 @远峰

// 统一的接口适配不同类
// Target 客户期望使用的接口
interface ComputerInterface {
  usb(): void;
}

// Adaptee 
class HuaweiPhone {
  huaweiInterface(): void {
    console.log('华为手机的数据接口');
  }
}

// Adaptee 
class Iphone {
  iphoneInterface(): void {
    console.log('苹果手机的数据接口');
  }
}

// Class Adapter 
class HuaweiDataWireAdapter extends HuaweiPhone implements ComputerInterface {
  usb(): void {
    console.log('使用华为数据线连接');
    super.huaweiInterface();
  }
}

class IphoneDataWireAdapter extends Iphone implements ComputerInterface {
  usb(): void {
    console.log('使用苹果数据线连接');
    super.iphoneInterface();
  }
}

function commonAdapterDemo() {
  const computer1 = new HuaweiDataWireAdapter();
  computer1.usb();
  const computer2 = new IphoneDataWireAdapter();
  computer2.usb();

}
commonAdapterDemo();
  • 有些误解就是一个适配器只用来适配一个类,但其实适配器模式也可以包装多个类。
  • 这个例子就是一个类适配器的应用。客户期望使用他们自己的数据线连接 ~.usb(),然后通过适配器做了一个转换,事实上没有说将华为手机和苹果手机的数据线接口给重新设计了~
  • [ ] 相类似的是外观模式,还没思考(? 狗带了)

NOTE: 外观和适配器模式都可以包装许多类,但是外观模式是为了简化操作,而适配器模式是将接口转换为不同接口

Q & A

  • 一个适配器需要做多少“适配”工作?
    适配器做的工作和目标接口的大小成正比

参考资料

你可能感兴趣的:(typescript,设计模式)