Adapter, 也称Wrapper, 指的是当接口不兼容时需要提供额外的类或实现来帮助接口转换.
这是一种结构型设计模式. 结构型设计模式往往需要组合, 聚合, 或是继承的机制来实现特定的结构. 尽管不同语言对于继承的限制不同(Java只允许单继承), 但使用结构型的设计模式时需要注意OCP(开闭原则).
Adapter可以是:

  • 类适配器
  • 对象适配器
  • 接口适配器

接下来的适配器讨论将基于Java进行.

使用时机

类适配器

听起来Adapter似乎是有些许亡羊补牢的意味, 因为当Adapter出现时, 为了实现接口的转变, 它一定会改变一个已有对象的接口.
不过, 如果已经知道未来可能会新增未知的接口, 那么提前写好可供将来Adapter实现的类/接口不失为一个好的选择.
比如, 当你使用类适配器时, 假设Client调用的Foo类需要使用InterfaceA, 而原有的代码只设计了一个Beta类用来满足业务需求, 那么在Java里, 想要重写Beta方法的直接手段就是继承它, 而又因为InterfaceA是接口, 继承Beta的类可以继续实现InterfaceA, 因此Client可以通过调用这个类满足Foo的接口需要. 这个类就是Adapter. 适配器模式 - 图1类适配器人如其名, 它是适配类的, 适配出来的是接口实现, 而继承所带来的资源耗费也使得类适配器应用场景较为单一. 而且当我们想适配该类的所有子类的时候就不能轻松实现.
总之, 在上面的例子中Adapter还因为继承Beta获得了一堆Beta方法. 类适配器有违OCP.

对象适配器

使用聚合来替代继承, Adapter现在需要持有一个Beta的实例. 对于InterfaceA, 同样需要实现, 只是形式上相较于类适配器略有差异.
此外, 在Client中使用Foo的时候, 有可能还需要为Foo所需要的Adapter提供合适的Beta对象.

对象适配器对于被适配的类重定义自由度更低.

需要考虑的因素

以如下角色为例: Client, Target(新接口), Adaptee(已存在接口, 需要适配), Adapter(适配器)

  • Adapter的匹配程度, Target和Adaptee的相似度越高越容易适配.
  • Adapter的可插入性, 尽量减少所需的依赖=>尝试进行接口适配这样一种Pluggable的做法
  • 双向适配器的透明特性, 接口适配器对于Target和Adaptee的角色的

    接口适配

    使用一个抽象类作为Adapter, 实现新接口的方法, 然后在Client使用Adapter的抽象实例时去覆写某一个会某些个方法: 适配器模式 - 图2Client可以在创建Adapter实例时再去覆写:
    1. AbsAdapter ada = new AbsAdapter(){
    2. @Override
    3. public void method2(){
    4. // Do something
    5. System.out.print("Implement method2")
    6. }
    7. }