设计模式之适配者模式

162 阅读5分钟

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口能够相互合作。这种模式通常用于系统升级或集成时,当现有的类无法直接使用时,提供一个包装类(适配器)来间接调用这些类的功能。

适配器模式分为两种:

  1. 类适配器模式:通过多重继承对一个接口与另一个接口进行匹配。类适配器使用继承来适配两个不兼容的接口。
  2. 对象适配器模式:通过组合来连接被适配者与目标接口。对象适配器使用组合的方式将请求转给被适配者。

适配器模式通常包含三个角色:

  1. 目标(Target)接口:当前系统业务所期待的接口,它可以是一个抽象类或接口。
  2. 需要适配的类(Adaptee):需要适配的对象或类型,它通常是一个具体的类,具有一些有用的行为,但其接口与当前系统不兼容。
  3. 适配器(Adapter)类:适配器模式的核心,它负责实现目标接口,同时包装一个被适配者对象,通过在内部调用被适配者的方法来实现目标接口。

适配器模式的实现步骤:

  1. 确定目标接口,这是你期望得到的接口。
  2. 设计适配器类,实现目标接口。
  3. 在适配器类中引用需要适配的对象。
  4. 在适配器类中,将目标接口的方法调用转换为对适配者类的相应方法的调用。
  5. 客户端代码可以使用目标接口与适配器进行交互。

举个例子来说明:

假设我们有一个只能通过闪电接口充电的iPhone和一个微型USB线充电器。这里iPhone是需要适配的类(Adaptee),微型USB充电器是目标接口(Target),我们需要一个适配器(Adapter)来连接这两个不兼容的接口。

// 目标接口
public interface LightningPhone {
    void recharge();
    void useLightning();
}

// 被适配的类
public class MicroUsbPhone {
    public void recharge() { /* 充电逻辑 */ }
    public void useMicroUsb() { /* 使用微型USB逻辑 */ }
}

// 适配器类
public class LightningToMicroUsbAdapter implements LightningPhone {
    private MicroUsbPhone microUsbPhone;

    public LightningToMicroUsbAdapter(MicroUsbPhone phone) {
        this.microUsbPhone = phone;
    }

    @Override
    public void recharge() {
        microUsbPhone.recharge();
    }

    @Override
    public void useLightning() {
        System.out.println("Using lightning adapter");
        microUsbPhone.useMicroUsb();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        LightningPhone lightningPhone = new LightningToMicroUsbAdapter(new MicroUsbPhone());
        lightningPhone.recharge();
        lightningPhone.useLightning();
    }
}

在上述例子中,适配器LightningToMicroUsbAdapter实现了LightningPhone接口,并在内部转换了接口调用以使用MicroUsbPhone的实现,从而允许我们通过适配器给iPhone充电。

类适配器模式(Class Adapter Pattern):

实现方式: 类适配器模式通过继承来实现适配器功能。

结构组成

  • 目标接口(Target):定义客户所需的特定领域的接口。
  • 被适配者(Adaptee):一个已经存在的接口,这个接口需要被适配。
  • 适配器(Adapter):对Adaptee的接口与Target接口进行适配;适配器是通过继承Adaptee并实现Target接口来建立Adaptee接口和Target接口之间的联系。

实现示例

假设我们有一个只能通过Lightning接口充电的iPhone(Target接口),我们有一个Micro-USB充电器(Adaptee),现在我们希望通过Micro-USB充电器给iPhone充电,我们可以使用类适配器模式。

// 目标接口
public interface LightningPort {
    void chargeWithLightning();
}

// 被适配者,假设这是一个已经存在的类,我们无法修改它
public class MicroUsbCharger {
    public void chargeWithMicroUsb() {
        System.out.println("Charging with Micro USB");
    }
}

// 适配器类
public class LightningToMicroUsbAdapter extends MicroUsbCharger implements LightningPort {
    @Override
    public void chargeWithLightning() {
        chargeWithMicroUsb();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        LightningPort charger = new LightningToMicroUsbAdapter();
        charger.chargeWithLightning();
    }
}

在类适配器模式中,适配器LightningToMicroUsbAdapter直接继承了MicroUsbCharger,这意味着它不仅实现了LightningPort接口,还继承了MicroUsbCharger的行为。

对象适配器模式(Object Adapter Pattern):

实现方式: 对象适配器模式通过组合来实现适配器功能。

结构组成

  • 目标接口(Target):定义客户所需的特定领域的接口。
  • 被适配者(Adaptee):一个已经存在的接口,这个接口需要被适配。
  • 适配器(Adapter):对Adaptee的接口与Target接口进行适配;适配器是通过包含一个Adaptee实例来建立Adaptee接口和Target接口之间的联系。

实现示例

使用与类适配器模式相同的例子,我们如何利用对象适配器模式来实现适配。

// 目标接口
public interface LightningPort {
    void chargeWithLightning();
}

// 被适配者
public class MicroUsbCharger {
    public void chargeWithMicroUsb() {
        System.out.println("Charging with Micro USB");
    }
}

// 适配器类
public class LightningToMicroUsbAdapter implements LightningPort {
    private MicroUsbCharger microUsbCharger;

    public LightningToMicroUsbAdapter(MicroUsbCharger charger) {
        this.microUsbCharger = charger;
    }

    @Override
    public void chargeWithLightning() {
        microUsbCharger.chargeWithMicroUsb();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        MicroUsbCharger microUsbCharger = new MicroUsbCharger();
        LightningPort charger = new LightningToMicroUsbAdapter(microUsbCharger);
        charger.chargeWithLightning();
    }
}

在对象适配器模式中,适配器LightningToMicroUsbAdapter不再继承MicroUsbCharger,而是持有一个MicroUsbCharger的引用。这样,适配器可以转发调用到MicroUsbCharger,从而使得我们可以通过Micro-USB充电器给iPhone充电。

类适配器模式与对象适配器模式的区别:

  1. 类适配器模式使用多继承对一个接口与另一个接口进行匹配。由于Java不支持多重类继承,因此在Java中不常用。
  2. 对象适配器模式使用组合的方式,即适配器内部持有一个被适配者的引用,然后在适配器的方法中,将调用转发给被适配者。
  3. 灵活性:对象适配器模式比类适配器模式更加灵活。因为对象适配器模式可以在运行时动态地组合被适配者,而类适配器模式在编译时就已经固定了。
  4. 目的:两种模式的目的相同,即允许不兼容的接口能够相互合作。

总的来说,对象适配器模式使用得更广泛,因为它更灵活,并且更符合组合优于继承的设计原则。当然,哪种模式更适合使用取决于具体的应用场景。