【设计模式】使用适配器模式做补偿设计

文章目录

  • 1.概述
  • 2.两种适配器模式
    • 2.1.类适配器
    • 2.2.对象适配器
  • 3.总结

1.概述

适配器模式是一种结构型设计模式,它提供了一个中间层,通过这个中间层,客户端可以使用统一的接口与具有不同接口的类进行交互,也就是说,将一个接口转换成客户期望的另一个接口,使得原本不兼容的接口能够协同工作。

举个现实中的例子,我们现在的很多轻薄笔记本为了减少厚度,一般不会设计网线的接口,或者说在笔记本上的可以插线的接口很少,这时候使用到的拓展坞就可以视为是一种适配器。
在这里插入图片描述


值得一提的是,与其他模式有点不同的是,适配器模式是一种补偿模式,主要用于解决现有的设计或实现与需求不匹配的问题,是在系统开发后期或者集成阶段,为了兼容已存在的、难以修改的组件接口或者为了统一不同接口之间的差异而采取的一种补救措施。

2.两种适配器模式

适配器模式有两种常见的实现形式:

  • 类适配器:通过继承的方式,子类(适配器)继承自需要被适配的类(适配者),并同时实现目标接口。
  • 对象适配器:通过组合的方式,适配器包含一个适配者的实例,并在自己的方法中调用适配者的功能来实现目标接口的方法。

2.1.类适配器

按照上面的描述,类图如下:
在这里插入图片描述

  • Target:目标接口,适配器将不适用于当前系统的接口,转换给目标接口的形状。
  • Adaptee:被适配的类,也就是被转换的对象。
  • Adapter:适配器

Client调用适配器,获取到转换成符合当前系统要求的数据。


这么看可能有点抽象,我们通过一个简单的业务场景来理解一下这种模式:

有一个客服系统,在了解到客户的需求后会往客户管理系统中推送线索,并且在客服系统中可以查看到销售对当前客户的跟进情况。现在由于旧客户管理系统日渐不满足使用要求了,于是建立了一个新的客户管理系统,客服系统需要从新的系统中获取到跟进数据。

但是,新旧两个客户系统对于跟进日志的接口定义不一样,这时候又不想对客服系统做大的改动,就可以使用适配器对接口进行转换,下面是简化过后的代码。

  • 旧系统的接口定义
    /*** 跟进记录对象*/
    @Data
    public class Record {/*** 跟进内容*/private String followContent;/*** 附件地址*/private String enclosure;
    }/*** 目标接口*/
    public interface RecordService {Record getRecord();
    }/*** 目标接口实现*/
    public class RecordServiceImpl implements RecordService {@Overridepublic Record getRecord() {// 模拟从老系统获取数据Record record = new Record();record.setFollowContent("跟进内容(老系统)");record.setEnclosure("附件地址(老系统)");return record;}
    }
    
  • 新系统中的定义
/*** 新系统沟通记录对象*/
@Data
public class NewRecord {/*** 沟通内容*/private String communicateContent;/*** 附件地址*/private String accessory;
}/*** 新系统接口*/
public interface NewRecordService {NewRecord getNewRecord();
}/*** 新系统接口实现*/
public class newRecordServiceImpl implements NewRecordService{@Overridepublic NewRecord getNewRecord() {// 模拟从新系统获取数据NewRecord newRecord = new NewRecord();newRecord.setCommunicateContent("跟进内容(新系统)");newRecord.setAccessory("附件地址(新系统)");return newRecord;}
}

实际情况相对于上面的代码可能会更加复杂,这里做演示就简化了一下代码,新旧系统主要是返回对象不一样,返回对象中的字段名不一样。

确定了之后编写适配器,按照类适配器的定义,我们先继承新接口的实现,再实现旧的模板接口

public class RecordAdapter extends newRecordServiceImpl implements RecordService {@Overridepublic Record getRecord() {NewRecord newRecord = super.getNewRecord();Record record = new Record();record.setFollowContent(newRecord.getCommunicateContent());record.setEnclosure(newRecord.getAccessory());return record;}
}

在适配器中,实现旧接口中的方法,并调用父类(新接口实现)的新的方法,然后将新接口返回的对象值封装到旧的日志对象中,做一下测试:

public class RecordAdapterTest {@Testpublic void testGetRecord() {RecordService recordService = new RecordServiceImpl();System.out.println(recordService.getRecord());recordService = new RecordAdapter();System.out.println(recordService.getRecord());}
}

Record(followContent=跟进内容(老系统), enclosure=附件地址(老系统))
Record(followContent=跟进内容(新系统), enclosure=附件地址(新系统))

可以看到,在字段名没变动的情况下,兼容了新系统的值。

通过适配器的方式,不需要修改新系统的接口,也不需要修改客服系统的上层业务代码,只需要在获取数据这一层做一下转换即可,返回给前端后,前端也不需要重新匹配字段,减少了代码的修改范围,降低了风险。


类适配器对这种简单的转换用起来比较方便,但是也存在比较大的缺陷:

  • 继承带来的常见问题,父类发生变化时,子类可能也需要被迫的跟着变化。
  • 对于Java这样的单继承语言来说,面对有多个需要被转换的对象时,就显得有点力不从心了。

所以,在大部分情况下,尤其是使用Java语言的情况下,更建议使用对象适配器

2.2.对象适配器

相对于类适配器,对象适配器能提供更高的灵活性和更低的耦合度,原理上也比较简单,就是将继承修改为组合,也就是这样。
在这里插入图片描述

将上面的适配器代码做一下修改,如下:

public class RecordAdapter2 implements RecordService {private NewRecordService newRecordService;public RecordAdapter2(NewRecordService newRecordService) {this.newRecordService = newRecordService;}@Overridepublic Record getRecord() {NewRecord newRecord = newRecordService.getNewRecord();Record record = new Record();record.setFollowContent(newRecord.getCommunicateContent());record.setEnclosure(newRecord.getAccessory());return record;}
}

在创建对象适配器时,将被适配的对象直接传入到适配器中即可,如果是Spring的服务,这些被适配的对象还可以自动依赖注入,也很方便。
使用对象适配器时,可以注入多个Adaptee,当目标对象需要的数据需要从多个不同的接口中查询出来再做聚合的时候,就可以使用这种方式来处理。用上面的代码来说就是,跟进记录附件地址需要从不同的接口进行查询的时候。

3.总结

本篇主要是将适配器模式的使用,作为一种补偿模式,不建议一开始就使用适配器模式,如果能够在设计初期尽可能的避免出现接口不兼容的情况,那么直接设计出符合需求的标准接口会更优。但毕竟没有完美的设计,当设计上存在一定的缺陷又没有资源做大重构的时候,适配器模式就派上用场了。

对于类适配器和对象适配器,区别就是在于类适配器通过继承实现,对象适配器通过组合实现,对于Java这样的单继承语言,更建议使用对象适配器,更加灵活。

再补充一下适配器的一些使用场景:

  • 替换依赖的系统:例如上面的那个例子
  • 接入第三方库或API:第三方的API或接口设计我们不能控制,可以用适配器将传输的报文转换成我们系统中的形式来落库。
  • 整合多个接口设计:例如一个短信服务中,对于短信发送的内容要做敏感词、黑词过滤,我们有自己的规则,不同的短信服务商也有自己的规则,可以用适配器将不同的规则整合起来,方便统一调用。
  • ……

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

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

相关文章

人工智能深度学习

目录 人工智能 深度学习 机器学习 神经网络 机器学习的范围 模式识别 数据挖掘 统计学习 计算机视觉 语音识别 自然语言处理 机器学习的方法 回归算法 神经网络 SVM(支持向量机) 聚类算法 降维算法 推荐算法 其他 机器学习的分类 机器…

Open AI — Sora 如何发挥其魔力 — 近距离观察该技术

OpenAI 的大模型 Sora 可以制作一整分钟的高质量视频。他们的工作成果表明,使视频生成模型更大是为现实世界创建多功能模拟器的好方法。Sora 是一种灵活的可视化数据模型。它可以创建不同长度、形状和大小的视频和图片,甚至可以创建长达一分钟的高清视频。我阅读了 OpenAI 的…

AWS安全组是什么?有什么用?

最近看到小伙伴在问,AWS安全组是什么?有什么用?今天我们大家就来简单聊聊,仅供参考哦! AWS安全组是什么?有什么用? 【回答】:AWS安全组是一种虚拟防火墙,用于控制进出…

【畅玩雾锁王国】雾锁王国服务器手动部署教程2024年

阿里云雾锁王国服务器搭建教程是基于计算巢服务,3分钟即可成功创建Enshrouded游戏服务器,阿里云8核32G雾锁王国专用游戏服务器90元1个月、271元3个月,阿里云服务器网aliyunfuwuqi.com亲自整理雾锁王国服务器详细搭建教程: 一、前…

游戏配置二级缓存一致性问题解决方案

游戏服务器进程在启动的时候,一般会把所有策划配置数据加载到内存里,将主键以及对应的记录存放在一个HashMap容器里,这称为一级缓存。部分功能可能还需要缓存其他数据,这些称为二级缓存。举个例子,对于如下的玩家升级表…

Elasticsearch:了解人工智能搜索算法

作者:来自 Elastic Jessica Taylor, Aditya Tripathi 人工智能工具无处不在,其原因并不神秘。 他们可以执行各种各样的任务并找到许多日常问题的解决方案。 但这些应用程序的好坏取决于它们的人工智能搜索算法。 简单来说,人工智能搜索算法是…

采用uniapp实现的银行卡卡片, 支持H5和微信小程序

采用uniapp-vue3实现的银行卡卡片 支持H5、微信小程序(其他小程序未测试过,可自行尝试) 可用于参考学习 可到插件市场下载尝试: https://ext.dcloud.net.cn/plugin?id16736 使用示例

《Python 语音转换简易速速上手小册》第2章 Python 编程基础(2024 最新版)

文章目录 2.1 Python 语言基础2.1.1 基础知识深入基础总结 2.1.2 主要案例:数据分析脚本案例介绍案例 Demo案例分析 2.1.3 扩展案例 1:自动化邮件发送案例介绍案例 Demo案例分析 2.1.4 扩展案例 2:网页数据抓取案例介绍案例 Demo案例分析 2.2…

将本地项目上传到svn服务端和git

一、SVN 1.创建svn库,下面生成了三个文件夹,branches指分支,trunk下可以放项目 2.在本地checkout,填入svn库的地址,因为是新建的,所以checkout的是空文件夹 把自己的项目复制到trunk下,在项目上 右键-TortoiseSVN-add add完之后 右键-svn commit 3.idea打开这个项目,将项目跟…

C++面试宝典第31题:有效的数独

题目 判断一个9 x 9的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 1、数字1-9在每一行只能出现一次。 2、数字1-9在每一列只能出现一次。 3、数字1-9在每一个以粗实线分隔的3 x 3宫内只能出现一次。 下图是一个部分填充的有效的数独,数独部分空格内已…

爬虫在网页抓取的过程中可能会遇到哪些问题?

在网页抓取(爬虫)过程中,开发者可能会遇到多种问题,以下是一些常见问题及其解决方案: 1. IP封锁: 问题:封IP是最常见的问题,抓取的目标网站会识别并封锁频繁请求的IP地址。 解决方案…

Js如何判断两个数组是否相等?

本文目录 1、通过数组自带方法比较2、通过循环判断3、toString()4、join()5、JSON.stringify() 日常开发,时不时会遇到需要判定2个数组是否相等的情况,需要实现考虑的场景有: 先判断长度,长度不等必然不等元素位置其他情况考虑 1…

Spring Boot中的@Scheduled注解:定时任务的原理与实现

1. 前言 本文将详细探讨Spring Boot中Scheduled注解的使用,包括其原理、实现流程、步骤和代码示例。通过本文,读者将能够了解如何在Spring Boot应用中轻松创建和管理定时任务。 2. Scheduled注解简介 在Spring框架中,Scheduled注解用于标记…

《Python 语音转换简易速速上手小册》第5章 音频数据处理(2024 最新版)

文章目录 5.1 音频数据的基本处理5.1.1 基础知识5.1.2 主要案例:音频剪辑工具案例介绍案例 Demo案例分析 5.1.3 扩展案例 1:自动音量调节器案例介绍案例 Demo案例分析 5.1.4 扩展案例 2:语音识别预处理案例介绍案例 Demo案例分析 5.2 使用 Py…

手把手教您安装2024最新版微信消息防撤回插件

文章目录 📖 介绍 📖🏡 环境 🏡📒 使用方法 📒📝 步骤一📝 步骤二 ⚓️ 相关链接 ⚓️ 📖 介绍 📖 本文与大家分享一个大神开发的2024最新版本的微信消息防撤…

Tomcat 学习之 Servlet

目录 1 Servlet 介绍 2 创建一个 Servlet 3 web.xml 介绍(不涉及 filter 和 listener 标签) 3.1 display-name 3.2 welcome-file-list 3.3 servlet 3.4 session-config 3.5 error-page 4 Tomcat 如何根据 URL 定位到 Servlet 5 执行 Servlet …

不破不立,那些年错过的Python

随着OpenAI的发展,Python的重要性不言而喻。不知你是否和我一样,不知道曾经说过多少次我要学Python,都没有执行起来… 近期我在知识库中更新了一波Python教程,选取了这一篇分享给大家。 前言 很多时候我们需要让程序变成交互性的…

Linux系统——nginx服务介绍

一、Nginx——高性能的Web服务端 Nginx的高并发性能优于httpd服务 1.nginx概述 Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始,第一次公开发布时间是2004年10月4日,版本…

第二证券:美国加息对中国股市的影响?美联储加息利好还是利空股市?

美国加息是一种紧缩的钱银政策,会招引出资者添加银行的出资,导致社会上的流动钱银减少,然后间接地导致股市流动资金减少,股市跌落,引起商场上的出资者恐慌,大量卖出,添加商场上的空方力量&#…

电路设计(25)——4位数字频率计的multism仿真及PCB设计

1.设计要求 使用4位数码管,显示输入信号的频率。完成功能仿真后,用AD软件,画出原理图以及PCB。 2.电路设计 输入信号的参数为: 可见,输入为168HZ,测量值为170HZ,误差在可接受的范围内。 3.PCB设…