前言
目前正在出一个设计模式专题
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
本节给大家讲一下设计模式中的适配器模式
,并结合实际业务场景给大家讲解如何使用~
本专题的所有案例代码主要以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
方法,该方法实际上是调用了 ThirdPartyLibrary
的 doSomethingElse
方法。通过适配器模式,我们成功地将第三方库的接口转换为了客户端代码需要的接口,使得客户端代码能够正常工作。
适配器模式在实际开发中经常被使用,特别是在集成不同系统或库时。例如,我们可能需要将一个旧的库或系统接口转换为新的接口,以便与现有的代码进行交互。适配器模式可以帮助我们快速地完成这种转换工作,提高代码的复用性和可维护性。
最佳实践
同样以电商平台为例,假设我们的电商平台需要集成多个不同的第三方物流服务提供商,这些物流服务提供商的接口不一致,我们可以使用适配器模式来统一物流服务接口,使得我们的电商平台可以适配多种物流服务提供商。具体实现代码如下:
首先,我们定义一个 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 专题学习
- 一起来学kafka之Kafka集群搭建
- 一起来学kafka之整合SpringBoot基本使用
- 一起来学kafka之整合SpringBoot深入使用(一)
- 一起来学kafka之整合SpringBoot深入使用(二)
- 一起来学kafka之整合SpringBoot深入使用(三)
项目源码(源码已更新 欢迎star⭐️)
ElasticSearch 专题学习
- 利用docker搭建es集群
- 一起来学ElasticSearch(一)
- 一起来学ElasticSearch(二)
- 一起来学ElasticSearch(三)
- 一起来学ElasticSearch(四)
- 一起来学ElasticSearch(五)
- 一起来学ElasticSearch(六)
- 一起来学ElasticSearch(七)
- 一起来学ElasticSearch(八)
- 一起来学ElasticSearch(九)
- 一起来学ElasticSearch(十)
- 一起来学ElasticSearch之整合SpringBoot(一)
- 一起来学ElasticSearch之整合SpringBoot(二)
- 一起来学ElasticSearch之整合SpringBoot(三)
项目源码(源码已更新 欢迎star⭐️)
往期并发编程内容推荐
- Java多线程专题之线程与进程概述
- Java多线程专题之线程类和接口入门
- Java多线程专题之进阶学习Thread(含源码分析)
- Java多线程专题之Callable、Future与FutureTask(含源码分析)
- 面试官: 有了解过线程组和线程优先级吗
- 面试官: 说一下线程的生命周期过程
- 面试官: 说一下线程间的通信
- 面试官: 说一下Java的共享内存模型
- 面试官: 有了解过指令重排吗,什么是happens-before
- 面试官: 有了解过volatile关键字吗 说说看
- 面试官: 有了解过Synchronized吗 说说看
- Java多线程专题之Lock锁的使用
- 面试官: 有了解过ReentrantLock的底层实现吗?说说看
- 面试官: 有了解过CAS和原子操作吗?说说看
- Java多线程专题之线程池的基本使用
- 面试官: 有了解过线程池的工作原理吗?说说看
- 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看
- 面试官: 阻塞队列有了解过吗?说说看
- 面试官: 阻塞队列的底层实现有了解过吗? 说说看
- 面试官: 同步容器和并发容器有用过吗? 说说看
- 面试官: CopyOnWrite容器有了解过吗? 说说看
- 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析)
- 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析)
- 面试官: CountDownLatch有了解过吗?说说看(源码剖析)
- 面试官: CyclicBarrier有了解过吗?说说看(源码剖析)
- 面试官: Phaser有了解过吗?说说看
- 面试官: Fork/Join 有了解过吗?说说看(含源码分析)
- 面试官: Stream并行流有了解过吗?说说看
推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)
- springboot-all
地址
: github.com/qiuChenglei…- SpringBoot系列教程合集
- 一起来学SpringCloud合集
- SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(一)
- SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(二)