一、什么是适配器模式
概念:
- 适配器模式是一种
结构型设计模式
,它将一个类的接口转换成客户端所期望的另一种接口,使得原本不兼容的类能够一起工作。适配器模式主要包括目标接口、适配器和被适配对象。目标接口定义了客户端所期望的接口,适配器实现目标接口,并持有被适配对象的引用,通过调用被适配对象的方法来完成目标接口的实现。
适配器模式的角色组成:
-
目标接口(Target Interface):目标接口是客户端所期望的接口,适配器模式将原始接口转换成目标接口,使得客户端可以通过目标接口来访问被适配对象。
-
适配器(Adapter):适配器是适配器模式的核心,它实现目标接口,并持有被适配对象的引用。适配器将客户端的请求转发给被适配对象,完成客户端所期望的功能。
-
被适配对象(Adaptee):被适配对象是需要被适配的类或接口,它包含了客户端所需要的功能。
适配器模式可以分为类适配器
和对象适配器
两种形式,它们在适配器的实现方式上有所不同:
- 类适配器:类适配器通过多重
继承
将适配器类(继承目标接口)与被适配类(被继承)连接起来,使得适配器具有被适配对象的功能。 - 对象适配器:对象适配器通过持有被适配对象的
引用
,将客户端的请求转发给被适配对象,实现目标接口的功能。
无论是类适配器还是对象适配器,它们的目的都是将被适配对象的接口转换成客户端所期望的接口,实现接口的兼容性。
二、适配器模式的Java实现示例
类适配器实现(继承能力):
java
// 目标接口
public interface Target {
void request();
}
// 被适配对象
public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee's specific request");
}
}
// 适配器类(继承目标接口,同时持有被适配对象的引用)
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target target = new Adapter();
target.request();
}
}
对象适配器实现(引用能力):
java
// 目标接口
public interface Target {
void request();
}
// 被适配对象
public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee's specific request");
}
}
// 适配器类(实现目标接口,持有被适配对象的引用)
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request();
}
}
以上是适配器模式的两种常见实现方式,它们分别使用了类继承和对象组合来实现适配器功能。根据具体的场景和需求选择适合的实现方式即可。
二、适配器模式的优点
-
代码复用性:适配器模式可以重复使用现有的类,通过适配器将其转换为目标接口,使得这些类可以在新的环境中复用。
-
系统可扩展性:适配器模式允许系统在不修改已有代码的情况下扩展功能,只需要新增适配器类即可。
-
统一接口:适配器模式可以将不同接口的类转换为统一的目标接口,从而统一了接口的使用方法,使得系统更加统一和一致。
-
解耦合性:适配器模式可以解耦已有类和目标接口之间的依赖关系,使得它们可以独立地进行演化和升级。
三、适配器模式的应用场景及示例
-
外部接口的适配: 当系统需要与外部的接口进行交互时,但外部接口的方法和系统内部定义的方法不一致,可以使用适配器模式将外部接口适配成系统需要的接口。
例如,系统需要调用支付宝支付接口,但系统内部定义的支付接口和支付宝的接口不一致,可以通过编写一个支付宝支付适配器来适配两者之间的差异。 -
数据库适配: 当系统需要切换数据库或使用不同的数据库连接方式时,可以使用适配器模式进行数据库适配。
例如,系统原来使用MySQL数据库,但需要切换到Oracle数据库,可以通过编写一个Oracle数据库适配器来适配两种不同的数据库。 -
GUI界面适配: 当系统需要在不同的操作系统上运行,且每个操作系统的GUI界面不同,可以使用适配器模式进行GUI界面适配。
例如,系统在Windows操作系统上运行时,需要使用Windows的GUI界面组件,而在Mac操作系统上运行时,需要使用Mac的GUI界面组件,可以通过编写不同操作系统的GUI适配器来适配不同的GUI界面。 -
日志适配: 当系统需要将日志输出到不同的日志系统,例如将日志同时输出到控制台和文件中,可以使用适配器模式进行日志适配。
例如,系统原来使用log4j作为日志输出组件,但需要切换到logback作为日志输出组件,可以通过编写一个logback的适配器来适配两种不同的日志输出组件。
五、SpringBoot中适配器模式的实现
适配器模式在Spring Boot中的使用示例:第三方支付服务
java
// 目标接口,定义了在业务中需要使用的方法
public interface PaymentService {
void pay(String paymentType, double amount);
}
// 第三方支付服务类,提供了第三方支付功能
@Component
public class ThirdPartyPaymentService {
public void makePayment(String type, double amount) {
// 调用第三方支付服务的接口进行支付
System.out.println("Making payment via " + type + ": $" + amount);
}
}
// 适配器类,将第三方支付服务类适配为目标接口
@Component
public class PaymentServiceAdapter implements PaymentService {
@Autowired
private ThirdPartyPaymentService thirdPartyPaymentService;
@Override
public void pay(String paymentType, double amount) {
// 调用第三方支付服务类的方法来完成支付
thirdPartyPaymentService.makePayment(paymentType, amount);
}
}
// 使用适配器模式进行支付
@SpringBootApplication
public class Main {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Main.class, args);
PaymentService paymentService = context.getBean(PaymentService.class);
// 使用适配器进行支付
paymentService.pay("Alipay", 100.0);
paymentService.pay("WeChat Pay", 200.0);
}
}
在这个示例中,我们使用Spring Boot来实现适配器模式。首先定义了目标接口PaymentService
,其中定义了支付的方法。然后有一个第三方支付服务类ThirdPartyPaymentService
,提供了第三方支付的功能,并且使用@Component
注解将其声明为Spring Bean。
适配器类PaymentServiceAdapter
同样使用@Component
注解将其声明为Spring Bean,并使用@Autowired
注解将ThirdPartyPaymentService
注入其中。适配器类实现了目标接口,并将第三方支付服务类进行适配。
在Main
类中,我们使用@SpringBootApplication
注解启动Spring Boot应用。通过ApplicationContext
从Spring容器中获取PaymentService
实例,然后使用适配器进行支付。
这个示例中的适配器模式应用于一个实际的业务场景,将第三方支付服务类适配为我们业务中需要的支付服务。同时,利用Spring Boot来管理和注入依赖,使得适配器模式的实现更加简洁和灵活。