连接多元世界的纽带——适配器模式的魅力

连接多元世界的纽带------适配器模式的魅力

📚 A公司正在开发一个电子商务平台,团队决定集成一个新的服务。例如支付宝、微信等第三方的支付选项给用户,然而,我们的服务之前的支付接口和它们的接口是不兼容的,导致无法直接继承,需要修改之前的代码,比较麻烦,我们想在不改变现有支付系统的前提下,将支付宝的支付系统集成在我们的平台中。

🙋‍♂️ 适配器模式就可以解决以上问题,通过创建一个适配器,我们可以使不兼容的系统相互调用。

在本篇文章中,我们就开始学习适配器模式吧~

1. 概述

适配器模式是通过引入一个叫做适配器 的包装类,将一个接口转换为客户希望的另一个接口(适配者),使这两个不兼容的接口可以在一个系统中工作。

🏷️ 适配器模式有两种表现形式,分别为类适配器模式对象适配器模式

  • 对象适配器: 适配器和适配者之间是关联关系;
  • 类适配器: 适配器和适配者之间是继承或者实现关系;
    ❗ 简单理解适配器模式

Java中的Arrays有个排序(sort)方法,只能对数组进行排序,但是如果我们想要对List排序,就需要引入一个适配器,对List做处理,调用Arrays中的排序方法实现这个功能。你懂了吗?😉

2. 结构

适配器模式由以下角色组成:

  • 目标抽象类(Target): 目标抽象类就是客户端直接调用的接口,可以是一个抽象类或接口,也可以是一个具体的类;
  • 适配器类(Adapter): 适配器类可以调用另一个接口,对目标抽象类适配者类适配,使二者产生联系,是适配器模式的核心;
  • 适配者类(Adaptee): 适配者类就是被适配的类,它是一个已经存在的接口,一般是一个具体的类,是客户端希望调用的方法;

3. UML图

  • 对象适配器
  • 类适配器

4. 实现

  • 对象适配器
csharp 复制代码
 // 目标抽象类
 class abstract Target {
     public abstract void method();
 }
csharp 复制代码
 // 适配者类
 class Apaptee {
     public void othermethod() {
         // 具体的实现逻辑
     }
 }
scala 复制代码
 // 适配器类
 class Adapter extends Target {
     private Adaptee adaptee; // 适配器中关联适配者
     
     public Adapter(Adaptee adaptee) {
         this.adaptee = adaptee;
     }
     
     // 适配器中可以直接调用适配者的具体方法
     public void methed() {
         adaptee.othermethod()
     }
 }
  • 类适配器
csharp 复制代码
 // 由于java是单继承,所以目标抽象类不能是抽象类,只能是接口
 interface Target {
     void method();
 }
csharp 复制代码
 // 适配者类
 class Apaptee {
     public void othermethod() {
         // 具体的实现逻辑
     }
 }
scala 复制代码
 // 适配器类
 class Adapter extends Adaptee implements Target {
     public void methed() {
         othermethod() // 由于继承了Adaptee类,可以直接使用othermethod方法
     }
 }

5. 案例分析

我们实现上述的A公司想要新增支付宝支付的功能实例代码。

0️⃣ 公司之前的支付接口代码

csharp 复制代码
 public interface PayService {
     void pay();
 }

1️⃣ 支付宝支付接口代码

csharp 复制代码
 public class AlipayService {
     void alipay() {
         System.out.println("支付宝支付");
     }
 }

2️⃣ 引入适配者类的代码

java 复制代码
 public class AlipayServiceAdapter implements PayService{
 ​
     private AlipayService alipayService;
 ​
     public AlipayServiceAdapter(AlipayService alipayService) {
         this.alipayService = alipayService;
     }
 ​
     @Override
     public void pay() {
         alipayService.alipay();
     }
 }

3️⃣ 客户端调用代码

java 复制代码
 public class Client {
     public static void main(String[] args) {
         AlipayService alipayService = new AlipayService();
         PayService payService = new AlipayServiceAdapter(alipayService);
         payService.pay();
     }
 }

✍ 上述代码使用了对象适配器模式,大家可以使用类适配器模式实现相同功能哦~

6. 优缺点

✅️ 优点:

  • 目标类和适配类解耦。引入适配器类重用现有的类就可以新增新的功能接口,无需修改原来的结构;
  • 单一职责。将接口或者数据的转换代码从系统的主要业务分离出来;

❌ 缺点:

  • 类适配器模式使用限制。由于Java语言不支持多继承,一次只能适配一个适配者类,不能适配多个;
  • 增加代码负责度。因为需要新增接口和类,比直接修改已有代码更复杂;

7. 使用场景

  • 系统需要使用现有类,而这些类和工程现有代码不兼容;
  • 复用一些类,它们处于同一继承体系,并且它们又有一些公共方法。

8. 扩展

8.1 双向适配器模式

双向适配器模式是适配器模式的一种变体,它允许两个不兼容的接口之间进行双向适配,就是适配器类中,支持对目标类和适配者的引用,这个适配器就是双向适配器

📚 B公司需要开发一个通信接口,它们之间需要使用双向适配器模式,下面是实现的代码。

typescript 复制代码
 public interface ServiceInterface {
     void sendMsgToClient(String msg);
 }
 ​
 public interface ClientInterface {
     void sendMsgToService(String msg);
 }
 ​
 public class Service implements ServiceInterface{
 ​
     @Override
     public void sendMsgToClient(String msg) {
         System.out.println("Service 接受到消息:" + msg);
     }
 }
 ​
 public class Client implements ServiceInterface{
 ​
     @Override
     public void sendMsgToClient(String msg) {
         System.out.println("Client 接收到消息:" + msg);
     }
 }
typescript 复制代码
 public class BidirectionalAdapter implements ServiceInterface, ClientInterface{
     private Service service;
     private Client client;
 ​
     public BidirectionalAdapter(Service service, Client client) {
         this.service = service;
         this.client = client;
     }
 ​
     @Override
     public void sendMsgToService(String msg) {
         service.sendMsgToClient(msg);
     }
 ​
     @Override
     public void sendMsgToClient(String msg) {
         client.sendMsgToClient(msg);
     }
 }
java 复制代码
 public class Main {
 ​
     public static void main(String[] args) {
         Service service = new Service();
         Client client = new Client();
 ​
         BidirectionalAdapter adapter = new BidirectionalAdapter(service, client);
         adapter.sendMsgToClient("service 的消息");
 ​
         adapter.sendMsgToService("client 的消息");
     }
 }

🪐 运行结果:

8.2 缺省适配器模式

缺省适配器模式也是适配器模式的一种变体,其应用比较广泛。当不需要实现一个接口提供的所有方法时,可先设计一个抽象类实现该接口,并为每一个方法提供一个空方法来覆盖父类的方法,那么抽象类的子类可以自己选择覆盖父类的方法实现需求。

缺省适配器模式适用于不想使用接口中的所有方法的情况。

缺省适配器模式中,包含3个角色:

  • 适配者接口(ServiceInterface): 是一个接口,定义了大量的方法;
  • 缺省适配器(DefaultAdapter): 缺省适配器的核心,使用空方法的实现了在适配者接口中声明的方法,通常为抽象类;
  • 具体业务(ConcreteService): 是缺省适配器类的子类,如果直接实现适配者接口,需要实现所有的方法,如果继承了缺省适配器,则只需要适配想要使用的方法;

📚 C公司需要开发一个界面显示的功能,定义了一个接口ViewService,里面定义了很多的方法,现在需要实现在某平台的显示功能,只需要实现其中的一部分方法,如果我们直接继承了ViewService,则需要实现所有的方法,其他方法为空方法,现在我们可以引入一个缺省适配器类ViewAdapter类,在后续增加功能时,只需要继承ViewAdapter类即可。请看下面代码

csharp 复制代码
 public interface ViewService {
     void showBanner();
 ​
     void showColor();
 ​
     void showButton();
 ​
     void showCmd();
 ​
     void showStyles();
 ​
     void showShape();
 }
less 复制代码
 public abstract class ViewAdapter implements ViewService{
     @Override
     public void showBanner() {
 ​
     }
 ​
     @Override
     public void showColor() {
 ​
     }
 ​
     @Override
     public void showButton() {
 ​
     }
 ​
     @Override
     public void showCmd() {
 ​
     }
 ​
     @Override
     public void showStyles() {
 ​
     }
 ​
     @Override
     public void showShape() {
 ​
     }
 }
scala 复制代码
 public class LinuxViewService extends ViewAdapter{
     // 只需要实现需要使用的方法
     @Override
     public void showCmd() {
         System.out.println("展示cmd框");
     }
 }

9. 总结

好了,我们这篇文章到此就要告一段落了,通过这篇文章,我们学会使用了适配器模式,以后如果在项目中遇到接口不兼容的问题,就要先考虑一下适配器模式,相信我们会写出更好的代码~

欢迎朋友们关注我的公众号📢📢📢:【码匠er】

我会持续更新关于技术的文章❤️🤎💚🧡💛

欢迎大家点赞👍 收藏 ⭐ 关注 💡三连支持一下~~~

查看文章过程中有问题或者有需要修改的地方,欢迎私聊我哦 🗨🗨🗨

不管世界变成什么样,我们都要加强自己自身能力~✊✊✊

相关推荐
间彧19 小时前
@ControllerAdvice与AOP切面编程在处理异常时有什么区别和各自的优势?
后端
间彧20 小时前
什么是Region多副本容灾
后端
爱敲代码的北20 小时前
WPF容器控件布局与应用学习笔记
后端
爱敲代码的北20 小时前
XAML语法与静态资源应用
后端
清空mega20 小时前
从零开始搭建 flask 博客实验(5)
后端·python·flask
爱敲代码的北20 小时前
UniformGrid 均匀网格布局学习笔记
后端
一只叫煤球的猫20 小时前
从1996到2025——细说Java锁的30年进化史
java·后端·性能优化
喵个咪20 小时前
开箱即用的GO后台管理系统 Kratos Admin - 数据脱敏和隐私保护
后端·go·protobuf
我是天龙_绍21 小时前
Java Object equal重写
后端
虎子_layor21 小时前
实现异步最常用的方式@Async,快速上手
后端·spring