适配器模式(Adapter Pattern)

原文地址:https://jaune162.blog/design-pattern/adapter-pattern.html
更多精彩文章请移步:https://jaune162.blog
更多专题系列文章请移步:https://books.jaune162.blog

序言

在软件开发的世界中,我们经常会遇到一个棘手的问题:随着系统的发展与迭代,新功能的需求不断涌现,而这些新功能往往需要与旧有系统进行交互。这就带来了一个挑战——新旧系统之间由于接口不兼容、数据格式不同或是通信协议有所差异等问题,导致无法直接协同工作。如何让这些原本因接口或功能不匹配的组件能够无缝对接,共同完成任务?

面对这一问题,适配器模式(Adapter Pattern)应运而生。适配器模式是一种结构型设计模式,它通过引入一个中间层——即“适配器”——来解决两个不兼容接口之间的矛盾。这个适配器充当转换器的角色,将一种接口转换成另一种客户端期望的接口,从而实现了原有功能的新用途。

就像电源插头与插座的关系一样,虽然电源插头的形状各异,但只要使用对应的转换器,就可以在不同标准的电源插座中供电。在软件设计中,适配器模式允许已有的类或模块通过引入适配器来复用,而无需修改原有代码,大大增强了系统的灵活性和可扩展性。

定义

Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

结构

想象这样一个场景,在微服务场景下,有一个接口升级,参数发生了变更。但是有其他服务在大量使用老版接口,为了不影响原有业务,需要确保老版接口依然可以正常使用。那这时候就需要一个适配层,接受老版参数,然后转为新版参数,再调用新版的业务接口处理相关的业务逻辑。

在这里插入图片描述

实现

@Data
public class ParamV2 {private String name;private String code;private Integer type;
}public interface ServiceV2 {void doService(ParamV2 param);
}public class ServiceV2Impl implements ServiceV2 {@Overridepublic void doService(ParamV2 param) {System.out.println("升级后的业务处理逻辑");}
}

V1版本接口适配V2版本接口

@Data
public class ParamV1 {private String name;private String code;
}public interface ServiceV1 {void doService(ParamV1 param);
}public class ServiceV2Adapter implements ServiceV1 {private final ServiceV2 serviceV2;public ServiceV2Adapter(ServiceV2 serviceV2) {this.serviceV2 = serviceV2;}@Overridepublic void doService(ParamV1 param) {ParamV2 paramV2 = new ParamV2();paramV2.setName(param.getName());paramV2.setCode(param.getCode());// 设置一个默认值paramV2.setType(1);System.out.println("旧版本业务类做参数转换");this.serviceV2.doService(paramV2);}
}

测试


public class Main {public static void main(String[] args) {ServiceV2 serviceV2 = new ServiceV2Impl();ServiceV1 serviceV1 = new ServiceV2Adapter(serviceV2);ParamV1 paramV1 = new ParamV1();paramV1.setName("张三");paramV1.setCode("zhangsan");serviceV1.doService(paramV1);}
}

输出

旧版本业务类做参数转换
升级后的业务处理逻辑

通过适配层,旧版本接口无需任何改动就可以适配新版本接口。这样可以减少大量的接口升级对业务系统的改动。

本例中仅是做参数的适配,也可以做业务接口适配,即抛开ServiceV2ServiceV2是一套新的业务逻辑。而在ServiceV2Adapter直接调用其他业务接口实现新版业务逻辑,而不必拘泥一定要转换为ServiceV2的参数,来调用ServiceV2的业务接口。
适配层的主要作用是做适配,只要完成了适配任务,我认为都是没有问题的。

实际的业务实例

系统中提供了一个公共的方法来给用户发送消息。但是不同的业务发送的消息不一致,如果订单过期提醒,和快递送达提醒。为了处理这种组装消息的差异,我们可以引入适配层,在适配层将消息组装成一致的消息,然后发送给用户。

在这里插入图片描述

而给用户发送消息又有多种形式,如短信提醒,站内信,钉钉提醒等形式,那又需要一个适配层,将这个消息对象转换为其他业务接口可以接收的消息参数。与上面的区别在于,上面的业务是在不同的业务中,将业务数据转换为统一的消息对象。而这里是要将消息对象转换为不同的三方接口参数。

在这里插入图片描述

InternalMessageSender 本身就可以处理 Message 类型的参数,所以无需适配层。而SmsMessageSender无法处理 Message 类型的参数,所以需要通过适配层做一次转换处理。

因为在系统中短信发送、钉钉消息发送类的与第三方对接的接口一般都是作为公共接口来使用的。如发送短信,如果每个需要发送短信的业务都单独写一套发送短信的对接接口,那系统中重复的代码将会很多。因此一般都是有一个公共的第三方对接接口,其他业务需要的时候通过类似于适配的功能,组装三方接口需要的参数,然后调用三方接口实现对应的业务。

以上逻辑的代码实现此处不再实现。

何时使用

  • 系统需要使用现有类,但其接口与系统要求的接口不兼容。
  • 需要在不改变已有类的情况下,将多个类的接口统一起来。
  • 需要在一个类中封装一些复杂的接口,以便其他类可以轻松地使用它。

适配器最终解决的还是不兼容的问题,一般是处理系统重已存在接口与新业务之间的兼容性问题。

与其他设计模式的联系

参考桥接模式:https://books.jaune162.com/docs/design-pattern/patterns/structural/bridge-pattern

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/279209.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java8中Stream流API最佳实践Lambda表达式使用示例

文章目录 一、创建流二、中间操作和收集操作筛选 filter去重distinct截取跳过映射合并多个流是否匹配任一元素:anyMatch是否匹配所有元素:allMatch是否未匹配所有元素:noneMatch获取任一元素findAny获取第一个元素findFirst归约数值流的使用中…

分布式接口幂等性解析

一、概述 幂等性定义:用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。【同一操作指的是同一个浏览器,发送相同的请求】。 常见场景: 提交订单接口。返回提交结果时网络出现故障&am…

UDF提权

目录 一、UDF概述 二、提权条件 三、漏洞复现 (一) 信息收集 1. Nmap信息收集 1.1、查看当前IP地址 1.2、扫描当前网段,找出目标机器 1.3、快速扫描目标机全端口 2. dirb目录扫描 3. 第一个flag 3.1、目录遍历漏洞 3.2、flag 4. 敏感信息利用 (二) 漏…

重学SpringBoot3-函数式Web

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-函数式Web 函数式Web编程简介RouterFunctionRequestPredicateServerRequestServerResponse 好处示例结论 随着响应式编程范式的兴起和 Java 函数式编程能…

腾讯云服务器多少钱一个月?5元1个月,这价格没谁了

2024腾讯云服务器多少钱一个月?5元1个月起,腾讯云轻量服务器4核16G12M带宽32元1个月、96元3个月,8核32G22M配置115元一个月、345元3个月,腾讯云轻量应用服务器61元一年折合5元一个月、4核8G12M配置646元15个月、2核4G5M服务器165元…

[QJS xmake] 非常简单地在Windows下编译QuickJS!

文章目录 前言准备C编译器xmake编译包 工程准备修改版本号第一遍编译第二遍编译效果 前言 quickjs是个很厉害的东西啊,我一直想编译一下的,奈何一直没成功。现在找了点时间成功编译了,写篇文章记录一下。当前版本:2024-1-13 应该…

插入排序算法记录

插入排序 1.基本思想:左侧的子序列总是有序的。对于每一个位置上的元素,将其与左侧已排序的部分进行比较并插入到合适的位置,直到整个序列有序 2.性能分析: 最好情况:如果输入数组已经是有序的,插入排序只…

原型模式(Clone)——创建型模式

原型模式(clone)——创建型模式 什么是原型模式? 原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需依赖它们所属的类。 总结:需要在继承体系下,实现一个clone接口,在这个方法中以本身作为拷…

【你也能从零基础学会网站开发】Web建站之jQuery进阶篇 jQuery自定义插件应用开发

🚀 个人主页 极客小俊 ✍🏻 作者简介:程序猿、设计师、技术分享 🐋 希望大家多多支持, 我们一起学习和进步! 🏅 欢迎评论 ❤️点赞💬评论 📂收藏 📂加关注 jQuery插件开发…

鸿蒙API9+axios封装一个通用工具类

使用方式: 打开Harmony第三方工具仓,找到axios,如图: 第三方工具仓网址:https://ohpm.openharmony.cn/#/cn/home 在你的项目执行命令:ohpm install ohos/axios 前提是你已经装好了ohpm ,如果没…

chatgpt大模型基础学习

chatgpt大模型基础学习 1. 吴恩达提示工程2. 大模型说的token是什么 1. 吴恩达提示工程 知乎 https://zhuanlan.zhihu.com/p/626290417?utm_id0 中文版 https://mp.weixin.qq.com/s?__bizMzkwMjQ5MzExMg&mid2247483714&idx1&sn5e905f5ec6196f6dc2187db2a8618f02&…

快速从0-1完成聊天室开发——环信ChatroomUIKit功能详解

聊天室是当下泛娱乐社交应用中最经典的玩法,通过调用环信的 IM SDK 接口,可以快速创建聊天室。如果想根据自己业务需求对聊天室应用的 UI界面、弹幕消息、礼物打赏系统等进行自定义设计,最高效的方式则是使用环信的 ChatroomUIKit 。 文档地址…

母亲的奶牛(bfs)

农夫约翰有三个容量分别为 A , B , C A,B,C A,B,C 升的挤奶桶。 最开始桶 A A A 和桶 B B B 都是空的,而桶 C C C 里装满了牛奶。 有时,约翰会将牛奶从一个桶倒到另一个桶中,直到被倒入牛奶的桶满了或者倒出牛奶的桶空了为止。 这一过…

基于YOLOv8的火焰烟雾实时检测系统【训练和系统源码+Pyside6+数据集+包运行】

✨目录 一、系统概述和展示🎄1.1 摘要 🎈 二、一站式使用教程🎄三、YOLOv8原理剖析🎄3.1 YOLOv8背景和技术原理🎈 四、模型训练、评估和推理🎄4.1 数据集介绍🎈4.2 模型训练🎈4.3 结…

【Swing】Java Swing实现省市区选择编辑器

【Swing】Java Swing实现省市区选择编辑器 1.需求描述2.需求实现3.效果展示 系统:Win10 JDK:1.8.0_351 IDEA:2022.3.3 1.需求描述 在公司的一个 Swing 的项目上需要实现一个选择省市区的编辑器,这还是第一次做这种编辑器&#xf…

慢sql优化

1.避免使用select *,而是明确列出需要的列, 2.小表驱动大表,in适用于左边大表,右边小表。 exists适用于左边小表,右边大表。 3.批量操作:如果每次插入数据库数据,都要连接一次数据库&#xf…

Java-SpringAop 编程式事物实现

SpringAop 编程式事物实现 1. 数据库事物特性 原子性 多个数据库操作是不可分割的,只有所有的操作都执行成功,事物才能被提交;只要有一个操作执行失败,那么所有的操作都要回滚,数据库状态必须回复到操作之前的状态 …

linux 安装常用软件

文件传输工具 sudo yum install –y lrzsz vim编辑器 sudo yum install -y vimDNS 查询 sudo yum install bind-utils用法可以参考文章 《掌握 DNS 查询技巧,dig 命令基本用法》 net-tools包 yum install net-tools -y简单用法: # 查看端口占用情况…

实现HBase表和RDB表的转化(附Java源码资源)

实现HBase表和RDB表的转化 一、引入 转化为HBase表的三大来源:RDB Table、Client API、Files 如何构造通用性的代码模板实现向HBase表的转换,是一个值得考虑的问题。这篇文章着重讲解RDB表向HBase表的转换。 首先,我们需要分别构造rdb和hba…

ModbusTCP转Profinet网关高低字节交换切换

背景:在现场设备与设备通迅之间通常涉及到从一种字节序(大端或小端)转换到另一种字节序。大端字节序是指高位字节存储在高地址处,而小端字节序是指低位字节存储在低地址处。在不动原有程序而又不想或不能添加程序下可选用ModbusTC…