一起来学设计模式之适配器模式

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 前言目前正在出一个设计模式专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~本节给大家讲一下设计模式中的适配器模式,并结合实际业务场景给大家讲解如何使用~本专题的所有案例代码主要以Java语言为主, 好了, 废话不多说直接开整吧~适配器模式适配器模式是一种结构型设计模式,其主要目的是将一个类的接口转换为另一个接口,以满足不同类之间的兼容性。

前言

目前正在出一个设计模式专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~

本节给大家讲一下设计模式中的适配器模式,并结合实际业务场景给大家讲解如何使用~

本专题的所有案例代码主要以Java语言为主, 好了, 废话不多说直接开整吧~

适配器模式

适配器模式是一种结构型设计模式,其主要目的是将一个类的接口转换为另一个接口,以满足不同类之间的兼容性

适配器模式涉及到以下角色:

  • 目标接口(Target):这是客户端代码想要使用的接口,但它与客户端代码原本持有的接口不同。
  • 源接口(Adaptee):这是客户端代码原本持有的接口,但它与目标接口不兼容。
  • 适配器(Adapter):这是一个转换器,将源接口转换为目标接口。

适配器模式可以分为两种类型:类适配器对象适配器

  • 类适配器:通过继承源接口和目标接口来实现适配器。这种方式要求源接口必须是一个类而不是一个接口,因此不太常用。
  • 对象适配器:通过持有一个源接口实例和目标接口实例来实现适配器。这种方式可以适用于源接口是一个接口或类的情况。

下面我们来看一个对象适配器的例子,假设我们有一个第三方库,它提供了一个名为 ThirdPartyLibrary 的类,该类的接口如下:

public class ThirdPartyLibrary {
    public void doSomethingElse(int value) {
        System.out.println("Doing something else with value: " + value);
    }
}

而我们的客户端代码中使用的是一个名为 OurLibraryInterface 的接口,其接口如下:

public interface OurLibraryInterface {
    void doSomething(int value);
}

我们现在需要将ThirdPartyLibrary的接口转换为 OurLibraryInterface 的接口,以便在客户端代码中使用。

我们可以通过对象适配器模式来实现这一目标。首先,我们定义一个适配器类 ThirdPartyLibraryAdapter,该类实现了 OurLibraryInterface 接口,并持有一个 ThirdPartyLibrary 实例:

接着,我们在客户端代码中创建一个 ThirdPartyLibrary 的实例,并使用适配器类 ThirdPartyLibraryAdapter 将其转换为 OurLibraryInterface 的接口:

public class AdapterTest {
    public static void main(String[] args) {
        // 创建第三方库实例
        ThirdPartyLibrary library = new ThirdPartyLibrary();
        // 创建适配器实例
        OurLibraryInterface adapter = new ThirdPartyLibraryAdapter(library);
        // 在客户端代码中使用适配器
        adapter.doSomething(42);
    }
}

在上面的示例中,我们创建了一个 ThirdPartyLibrary 的实例,并通过适配器类 ThirdPartyLibraryAdapter 将其转换为 OurLibraryInterface 的接口。然后我们在客户端代码中使用适配器实例调用了 doSomething 方法,该方法实际上是调用了 ThirdPartyLibrarydoSomethingElse 方法。通过适配器模式,我们成功地将第三方库的接口转换为了客户端代码需要的接口,使得客户端代码能够正常工作。

适配器模式在实际开发中经常被使用,特别是在集成不同系统或库时。例如,我们可能需要将一个旧的库或系统接口转换为新的接口,以便与现有的代码进行交互。适配器模式可以帮助我们快速地完成这种转换工作,提高代码的复用性和可维护性。

最佳实践

同样以电商平台为例,假设我们的电商平台需要集成多个不同的第三方物流服务提供商,这些物流服务提供商的接口不一致,我们可以使用适配器模式来统一物流服务接口,使得我们的电商平台可以适配多种物流服务提供商。具体实现代码如下:

首先,我们定义一个 LogisticsService 接口,包含了电商平台需要的物流服务功能:

public interface LogisticsService {
    void createOrder(String orderId, String senderAddress, String receiverAddress);
    void cancelOrder(String orderId);
    void queryOrder(String orderId);
}

然后,我们创建一个适配器接口 LogisticsServiceAdapter,它用于适配不同的物流服务提供商接口:

public interface LogisticsServiceAdapter {
    void createOrder(String orderId, String senderAddress, String receiverAddress);
    void cancelOrder(String orderId);
    void queryOrder(String orderId);
}

接着,我们创建多个不同的物流服务提供商接口实现类:

  • 顺丰物流
public class SFExpressService {
    public void createShipment(String orderId, String senderAddress, String receiverAddress) {
        System.out.println("SF Express created shipment for order " + orderId + " from " + senderAddress + " to " + receiverAddress);
    }
    public void cancelShipment(String orderId) {
        System.out.println("SF Express cancelled shipment for order " + orderId);
    }
    public void queryShipment(String orderId) {
        System.out.println("SF Express queried shipment for order " + orderId);
    }
}
  • 韵达物流
public class YundaExpressService {
    public void createOrder(String orderId, String senderAddress, String receiverAddress) {
        System.out.println("Yunda Express created order for " + orderId + " from " + senderAddress + " to " + receiverAddress);
    }
    public void cancelOrder(String orderId) {
        System.out.println("Yunda Express cancelled order for " + orderId);
    }
    public void getOrderStatus(String orderId) {
        System.out.println("Yunda Express queried order status for " + orderId);
    }
}

接着,我们创建适配器类 SFExpressServiceAdapter,它封装了顺丰快递的接口,并将其转换为 LogisticsServiceAdapter 接口的实现:


public class SFExpressServiceAdapter implements LogisticsServiceAdapter {
    private SFExpressService sfExpressService;
    public SFExpressServiceAdapter(SFExpressService sfExpressService) {
        this.sfExpressService = sfExpressService;
    }
    @Override
    public void createOrder(String orderId, String senderAddress, String receiverAddress) {
        sfExpressService.createShipment(orderId, senderAddress, receiverAddress);
    }
    @Override
    public void cancelOrder(String orderId) {
        sfExpressService.cancelShipment(orderId);
    }
    @Override
    public void queryOrder(String orderId) {
        sfExpressService.queryShipment(orderId);
    }
}

同样的韵达也是这样:

public class YundaExpressServiceAdapter implements LogisticsServiceAdapter {
    private YundaExpressService yundaService;
    public YundaExpressServiceAdapter(YundaExpressService yundaService) {
        this.yundaService = yundaService;
    }
    @Override
    public void createOrder(String orderId, String senderAddress, String receiverAddress) {
        yundaService.createOrder(orderId, senderAddress, receiverAddress);
    }
    @Override
    public void cancelOrder(String orderId) {
        yundaService.cancelOrder(orderId);
    }
    @Override
    public void queryOrder(String orderId) {
        yundaService.getOrderStatus(orderId);
    }
}

最后我们实现物流平台的功能服务,对其接口进行封装

public class LogisticsPlatformService implements LogisticsService{
    private LogisticsServiceAdapter logisticsServiceAdapter;
    public LogisticsPlatformService(LogisticsServiceAdapter logisticsServiceAdapter) {
        this.logisticsServiceAdapter = logisticsServiceAdapter;
    }
    @Override
    public void createOrder(String orderId, String senderAddress, String receiverAddress) {
        logisticsServiceAdapter.createOrder(orderId, senderAddress, receiverAddress);
    }
    @Override
    public void cancelOrder(String orderId) {
        logisticsServiceAdapter.cancelOrder(orderId);
    }
    @Override
    public void queryOrder(String orderId) {
        logisticsServiceAdapter.queryOrder(orderId);
    }
}

接着,测试一下:

public class LogisticsPlatformServiceTest {
    public static void main(String[] args) throws Exception {
        SFExpressService sfExpressService = new SFExpressService();
        LogisticsServiceAdapter sfAdapter = new SFExpressServiceAdapter(sfExpressService);
        LogisticsService service = new LogisticsPlatformService(sfAdapter);
        service.cancelOrder("顺丰订单取消");
    }
}

输出:

SF Express cancelled shipment for order 顺丰订单取消

需要注意的是,在使用适配器模式时,应该尽量避免出现大量的嵌套适配器。如果需要多次适配,建议对原接口进行重构,尽量减少适配器的使用次数,以提高代码的可维护性和可读性。

结束语

设计模式其实并不难,大家在学习的时候一定要在理解的基础上去写代码,不要去背代码。下节给大家讲桥接模式~

本着把自己知道的都告诉大家,如果本文对您有所帮助,点赞+关注鼓励一下呗~

相关文章

项目源码(源码已更新 欢迎star⭐️)

Kafka 专题学习

项目源码(源码已更新 欢迎star⭐️)

ElasticSearch 专题学习

项目源码(源码已更新 欢迎star⭐️)

往期并发编程内容推荐

推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

博客(阅读体验较佳)




相关文章
|
4天前
|
设计模式 Java API
重构旧代码的秘诀:用设计模式 - 适配器模式(Adapter)给Java项目带来新生
【4月更文挑战第7天】适配器模式是解决接口不兼容问题的结构型设计模式,通过引入适配器类实现目标接口并持有不兼容类引用,实现旧代码与新接口的协作。适用于处理兼容性问题、整合遗留代码和集成第三方库。应用时,识别不兼容接口,创建适配器类转换方法调用,然后替换原有引用。注意保持适配器简单、使用组合和考虑扩展性。过度使用可能导致系统复杂和维护成本增加,应谨慎使用。
|
4天前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
40 4
|
4天前
|
设计模式 存储 数据库
设计模式之适配器模式
设计模式之适配器模式
|
4天前
|
设计模式 Java Go
【设计模式】适配器模式怎么理解?
【设计模式】适配器模式怎么理解?
8 1
|
4天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~结构型]不兼容结构的协调——适配器模式
[设计模式Java实现附plantuml源码~结构型]不兼容结构的协调——适配器模式
|
4天前
|
设计模式 Go
[设计模式 Go实现] 结构型~适配器模式
[设计模式 Go实现] 结构型~适配器模式
|
4天前
|
设计模式 Java
【设计模式系列笔记】适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一种接口。它允许原本由于接口不匹配而无法一起工作的类能够协同工作。适配器模式通常涉及一个称为适配器的类,它充当两个不兼容接口之间的桥梁。
40 6
|
4天前
|
设计模式 Java 数据库
小谈设计模式(18)—适配器模式
小谈设计模式(18)—适配器模式
|
4天前
|
设计模式 算法 API
适配器模式:C++设计模式中的瑞士军刀
适配器模式:C++设计模式中的瑞士军刀
51 0
|
4天前
|
设计模式
设计模式之适配器模式
设计模式之适配器模式