适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口能够相互合作。这种模式通常用于系统升级或集成时,当现有的类无法直接使用时,提供一个包装类(适配器)来间接调用这些类的功能。
适配器模式分为两种:
- 类适配器模式:通过多重继承对一个接口与另一个接口进行匹配。类适配器使用继承来适配两个不兼容的接口。
- 对象适配器模式:通过组合来连接被适配者与目标接口。对象适配器使用组合的方式将请求转给被适配者。
适配器模式通常包含三个角色:
- 目标(Target)接口:当前系统业务所期待的接口,它可以是一个抽象类或接口。
- 需要适配的类(Adaptee):需要适配的对象或类型,它通常是一个具体的类,具有一些有用的行为,但其接口与当前系统不兼容。
- 适配器(Adapter)类:适配器模式的核心,它负责实现目标接口,同时包装一个被适配者对象,通过在内部调用被适配者的方法来实现目标接口。
适配器模式的实现步骤:
- 确定目标接口,这是你期望得到的接口。
- 设计适配器类,实现目标接口。
- 在适配器类中引用需要适配的对象。
- 在适配器类中,将目标接口的方法调用转换为对适配者类的相应方法的调用。
- 客户端代码可以使用目标接口与适配器进行交互。
举个例子来说明:
假设我们有一个只能通过闪电接口充电的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充电。
类适配器模式与对象适配器模式的区别:
- 类适配器模式使用多继承对一个接口与另一个接口进行匹配。由于Java不支持多重类继承,因此在Java中不常用。
- 对象适配器模式使用组合的方式,即适配器内部持有一个被适配者的引用,然后在适配器的方法中,将调用转发给被适配者。
- 灵活性:对象适配器模式比类适配器模式更加灵活。因为对象适配器模式可以在运行时动态地组合被适配者,而类适配器模式在编译时就已经固定了。
- 目的:两种模式的目的相同,即允许不兼容的接口能够相互合作。
总的来说,对象适配器模式使用得更广泛,因为它更灵活,并且更符合组合优于继承的设计原则。当然,哪种模式更适合使用取决于具体的应用场景。