适配器模式(Adapter)


目的
将类的接口转换为客户端期望的另一个接口。适配器允许类一起工作,否则由于接口不兼容而无法一起工作。

说明
您的存储卡中有一些照片,需要将它们传输到计算机上。为了传输它们,您需要某种与您的计算机端口兼容的适配器,以便您可以将存储卡连接到您的计算机。在这种情况下,读卡器就是是适配器。另一个例子是电源适配器,三脚插头不能连接到双脚插座,需要使用电源适配器,使其与双脚插座兼容。另一个例子是翻译将一个人所说的话翻译给另一个人。

简而言之
适配器模式允许您在适配器中包装一个原本不兼容的对象,使其与另一个类兼容。

维基百科说
在软件工程中,适配器模式是一种软件设计模式,它允许将现有类的接口用作另一个接口。它通常用于在不修改源代码的情况下使现有类与其他类一起工作。

程序示例
考虑一个只会使用划艇但根本不能驾船的船长。
首先我们要有划艇和渔船的接口

public interface RowingBoat {
  void row();
}

public class FishingBoat {
  private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
  public void sail() {
    LOGGER.info("The fishing boat is sailing");
  }
}

其次船长期望划艇接口的实现能够移动

public class Captain implements RowingBoat {

  private RowingBoat rowingBoat;

  public Captain(RowingBoat rowingBoat) {
    this.rowingBoat = rowingBoat;
  }

  @Override
  public void row() {
    rowingBoat.row();
  }
}

现在假设海盗来了,我们的船长需要逃离,但只有渔船可用。我们需要创建一个适配器,允许船长用他的划艇技能操作渔船。

public class FishingBoatAdapter implements RowingBoat {

  private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);

  private FishingBoat boat;

  public FishingBoatAdapter() {
    boat = new FishingBoat();
  }

  @Override
  public void row() {
    boat.sail();
  }
}

现在船长可以用渔船来躲避海盗。

Captain captain = new Captain(new FishingBoatAdapter());
captain.row();

适用场景

  • 您想使用现有的类,但它的接口与您需要的接口不匹配
  • 你想创建一个可重用的类,让它与不相关或不可预见的类(即不一定具有兼容接口的类)协作。
  • 你需要使用几个现有的子类,但通过对每个子类进行子类化来调整它们的接口是不切实际的。对象适配器可以调整其父类的接口。
  • 大多数使用第三方库的应用程序使用适配器作为应用程序和第三方库之间的中间层,以将应用程序与库分离。如果必须使用另一个库,则只需要新库的适配器,而无需更改应用程序代码。

后果:
类适配器和对象适配器有不同的权衡。
类适配器
  • 通过提交到具体的adaptee类使adaptee适应目标。因此,当我们想要调整类及其所有子类时,类适配器将不起作用。
  • 让适配器重写适配者(Adaptee)的一些行为,因为适配器是适配者的子类。
  • 只引入一个对象,不需要额外的指针间接指向适配者。

对象适配器
  • 一个适配器可以把许多适配者类和它的子类都适配到目标接口。适配器还可以立即向所有适配者添加功能。
  • 使得置换适配者行为变得非常困难。它将需要先子类化Adaptee,再使适配器适配子类而不是Adaptee本身。