设计模式学习[15]---适配器模式

文章目录

  • 前言
  • 1.引例
  • 2.适配器模式
    • 2.1 对象适配器
    • 2.2 类适配器
  • 总结

前言

这个模式其实在日常生活中有点常见,比如我们的手机取消了 3.5 m m 3.5mm 3.5mm的接口,只留下了一个 T y p e − C Type-C TypeC的接口,但是我现在有一个 3.5 m m 3.5mm 3.5mm的耳机接口,那怎么让耳机和手机相连?

当然是买个转接头或者转接线,一头是 3.5 m m 3.5mm 3.5mm圆孔一头是 t y p e − c type-c typec接口。
那这里的转接头或者转接线,充当的就是适配器。我手机只有type-c的接口,现在要让 3.5 m m 3.5mm 3.5mm的插头适配 t y p e − c type-c typec,就需要这个适配器。

这篇博客就写一下适配器模式,看看在软件开发里面,什么时候用适配器,又是怎么用的适配器。

1.引例

我们日常写代码,一般都在debug版本下写,调试程序也是这样。但是我们要发布程序的时候,肯定是要release版本发布的。发布给客户的软件出现了bug,崩溃了,如何快速定位?这又不是我们VS里面一个F5开始调试就能搞定的,这时候就需要根据日志文件来判断了,说到这,其实就我近期开发的模块,日志量确实不太够,惭愧。

写日志我们通常是把他写到一个log.txt这样的文件里面去,现在定义这样的一个写日志文件操作的类
在这里插入图片描述

对于这个日志类,我们在main函数中一般可以这样用:

LogToFile* plog=new LogToFile();
plog->initfile();
plog->writetofile("向日志文件中写入一条日志");
plog->readfromfile();
plog->closefile();
delete plog;

如果程序运行很久,日志越来越多,各种模块的日志信息都往这个文件添加,就会导致日志文件过大,这时候需要将日志写到文件变成写到数据库。对于这种情况,其实就是新的设计与实现,具体类如下:
在这里插入图片描述

对于这个日志写到数据库的类,我们在main函数中一般可以这样用:

LogToDatabase* plog=new LogToDatabase();
plog->initdb();
plog->writetodb("向日志文件中写入一条日志");
plog->readfromdb();
plog->closedb();
delete plog;

上面是写日志的两种方式,我们可以看到他们的实现很不一样,一个对文件操作,一个对数据库操作。

现在考虑这种情况,数据库在某一天突然G了,可能因为网络问题导致无法和数据库连接。那上面的第二种写日志的方式似乎就用不了了,我们还得用回第一种方式,但这时候又来问题了。我们目前使用的方案是数据库方案,代码都是基于LogToDatabase类的接口,而LogToDatabase类的接口和LogToFile类又不一样,咋办?

这个就相当于我们耳机一直是用type-c连手机,突然有一天手机type-c口坏了,蓝牙坏了,我们只能用有线3.5mm接口耳机,这时候咋办?转接头呀!


2.适配器模式

在不改变老日志系统源码的情况下,通过引入适配器,将使用新日志系统的项目与老日志系统接驳起来,此时,适配器扮演一个中间人的角色,将项目中针对新日志系统的接口调用转换成对应的老日志系统的接口调用,从而达到新接口适配老接口的目的,这就是适配器模式的工作

在这里插入图片描述
在这里插入图片描述

接下来是考虑适配的实现方式了,这里适配器的实现分为两种:对象适配器类适配器

前者是通过类与类之间的组合关系,也就是一个类的定义中含有其他类型的成员变量。这种关系实现了委托机制,即成员函数把功能的实现委托给了其他类的成员函数,当然需要持有一个其他类的指针,才可以实现委托。

后者则是通过类与类之间的继承关系来实现接口的适配,适配器类和和适配者类之间是继承关系。


2.1 对象适配器

在适配器模式中,一般分为三种角色

Target(目标抽象型):该类定义所需要暴露的接口,这些接口就是调用者希望使用的接口,也就是客户端需要用到的接口。这里是指LogToDatabase类。

Adaptee(适配者类):这个类表示的是被适配的角色,通常是指老接口。需要用被适配。这里是指LogToFile类。

Adapter(适配器类):这个就是适配器了,充当转换器的作用,是适配模式的核心。这里的作用就是把客户端针对LogToDatabase类的接口调用转换成对LogToFile(旧接口)的调用。

参考一下UML类图,在对象适配器中,我们需要让适配器继承目标抽象型LogToDatabase,因为它是对外暴露的接口。
其次,适配器需要有老接口类的指针,用来调用老接口。
在这里插入图片描述

现在具体看一下代码:

在这里插入图片描述

在这个类中,我们通过在适配器类LogAdapter中定义一个LogToFile的指针,在外层暴露的initdb,writetodb等接口中,调用老的接口。这样就做到了接口的适配,用同一套对外暴露的接口,实现底层的适配。

适配器模式与装饰模式有类似的地方,两者都使用了类与类之间的组合关系,但两者的实现意图是不同的,适配器模式是将原有的接口适配成另外一个接口,而装饰模式是对原有功能的增强,而且无论装饰多少层,装饰模式的调用接口始终不发生改变。

2.2 类适配器

先看UML,这里适配器类内部不再持有旧接口的指针,而也是用继承关系来做。
在这里插入图片描述

依照UML,我们的具体代码如下:

在这里插入图片描述

这里我们对于目标类LogToDatabase使用的是公有继承,对于旧接口LogToFile类,我们使用的是私有继承。
这里public继承表示的时一种 is-a 关系,也就是通过子类产生的对象一定也是一个父类对象,子类继承了父类的接口。
但是private继承就不是这种关系了,是一种组合关系,是根据…实现出的关系。
这里我们对旧接口私有继承就表示想通过LogToFile类实现出LogAdapter的意思。

这种多重继承的方式来做类适配器,在具体代码的实现中,我们可以直接调用LogToFile接口,不再需要特定的指针。看起来好像很不错,但是实际上是不提倡用类适配器的。

从灵活性上来说,类适配器不如对象适配器,因为private继承方式限制了LogAdapter能调用的LogToFile中的接口。
假如有下面的情况:

class ParClass{....}
class LogToFile:public ParClass{....}

采用对象适配器的话,我只需要在里面定一个ParClass* m_pfile指针,这个指针可以指向任何ParClass的子类对象,有时候这个子类对象可能不止一个。但如果是多重继承,我们需要继承的就不止这一个类了。

总结

一般来说,过多使用适配器模式并不见得是一件好事,因为从表面上看,调用的是A接口,但内部被适配成了调用B接口,这比较容易让人迷惑,一般都是在开发后期不得已才使用这种设计模式。所以,在很多情况下,如果方便对系统进行重构的话,那么以重构来取代适配也许更好。但软件开发中也存在时常要发布新版本的情况,新版本也存在与老版本的兼容性问题,有时完全抛弃老版本并不现实,所以才借助适配器模式使新老版本兼容。在遗留代码的复用、类库的迁移等工作方面,适配器模式仍旧能发挥巨大的作用。

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

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

相关文章

【简博士统计学习方法】第1章:2. 统计学习方法的基本分类

2. 统计学习方法的基本分类 监督学习所学习的数据都是已经标注过的;无监督学习所学习的数据没有标注信息;半监督学习只含有少量标注,大多数没有标注(利用已标注的数据来学习去标注未标注的数据) 2.1 监督学习 图里的…

Unity3d 基于Barracuda推理库和YOLO算法实现对象检测功能

前言 近年来,随着AI技术的发展,在游戏引擎中实现和运行机器学习模型的需求也逐渐显现。Unity3d引擎官方推出深度学习推理框架–Barracuda ,旨在帮助开发者在Unity3d中轻松地实现和运行机器学习模型,它的主要功能是支持在 Unity 中…

IEC61850遥控-增强安全选控是什么?

摘要:遥控服务是IEC61850协议中非常重要的一项服务,其通常会被应用在电源开关、指示灯、档位调节等器件的操作。 遥控是一类比较特殊的操作,其通过远程方式操作指定的设备器件,在一些重要的场景中需要有严谨的机制来进行约束&…

[免费]微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端)【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的微信小程序(高校就业)招聘系统(Springboot后端Vue管理端),分享下哈。 项目视频演示 【免费】微信小程序(高校就业)招聘系统(Springboot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项目介绍…

基于vue的商城小程序的毕业设计与实现(源码及报告)

环境搭建 ☞☞☞ ​​​Vue入手篇(一),防踩雷(全网最详细教程)_vue force-CSDN博客 目录 一、功能介绍 二、登录注册功能 三、首页 四、项目截图 五、源码获取 一、功能介绍 用户信息展示:页面顶部设有用户头像和昵称展示区,方便用户识别…

IDEA配置maven和git并如何使用maven打包和git推送到gitlab

首先找到设置 在里面输入maven然后找到点击 然后点击右边两个选项 路径选择下载的maven目录下的settings文件和新建的repository文件夹 点击apply应用 然后在搜索框里搜git点击进去 此路径为git的exe执行文件所在目录,选好之后点击test测试下方出现git版本号表…

04、Redis深入数据结构

一、简单动态字符串SDS 无论是Redis中的key还是value,其基础数据类型都是字符串。如,Hash型value的field与value的类型,List型,Set型,ZSet型value的元素的类型等都是字符串。redis没有使用传统C中的字符串而是自定义了…

Python教程丨Python环境搭建 (含IDE安装)——保姆级教程!

工欲善其事,必先利其器。 学习Python的第一步不要再加收藏夹了!提高执行力,先给自己装好Python。 1. Python 下载 1.1. 下载安装包 既然要下载Python,我们直接进入python官网下载即可 Python 官网:Welcome to Pyt…

springmvc前端传参,后端接收

RequestMapping注解 Target({ElementType.METHOD, ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented Mapping public interface RequestMapping {String name() default "";AliasFor("path")String[] value() default {};AliasFor(&quo…

数据库环境安装(day1)

网址:MySQL 下载(环境准备): (2-5点击此处,然后选择合适的版本) 1.linux在线YUM仓库 下载/安装: wget https://repo.mysql.com//mysql84-community-release-el9-1.noarch.rpm rpm -i https://r…

【MySQL系列文章】Linux环境下安装部署MySQL

前言 本次安装部署主要针对Linux环境进行安装部署操作,系统位数64 getconf LONG_BIT 64MySQL版本:v5.7.38 一、下载MySQL MySQL下载地址:MySQL :: Download MySQL Community Server (Archived Versions) 二、上传MySQL压缩包到Linuxx环境&#xff0c…

eNSP之家----ACL实验入门实例详解(Access Control List访问控制列表)(重要重要重要的事说三遍)

ACL实验(Access Control List访问控制列表)是一种基于包过滤的访问控制技术,它可以根据设定的条件对接口上的数据包进行过滤,允许其通过或丢弃。访问控制列表被广泛地应用于路由器和三层交换机。 准备工作 在eNSP里面部署设备&a…

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize() 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…

《零基础Go语言算法实战》【题目 1-14】字符串的替换

《零基础Go语言算法实战》 【题目 1-14】字符串的替换 请编写一个函数,将字符串中的空格全部替换为“%20”。假定该字符串有足够的空间存 放新增的字符,并且知道字符串的真实长度(≤ 1000),同时保证字符串由大小写的…

WebSocket 测试入门篇

Websocket 是一种用于 H5 浏览器的实时通讯协议,可以做到数据的实时推送,可适用于广泛的工作环境,例如客服系统、物联网数据传输系统, 基础介绍 我们平常接触最多的是 http 协议的接口,http 协议是请求与响应的模式&…

音视频入门基础:MPEG2-PS专题(6)——FFmpeg源码中,获取PS流的视频信息的实现

音视频入门基础:MPEG2-PS专题系列文章: 音视频入门基础:MPEG2-PS专题(1)——MPEG2-PS官方文档下载 音视频入门基础:MPEG2-PS专题(2)——使用FFmpeg命令生成ps文件 音视频入门基础…

代码随想录算法训练营day27

代码随想录算法训练营 —day27 文章目录 代码随想录算法训练营前言一、贪心算法理论基础二、455.分发饼干三、376. 摆动序列53. 最大子数组和总结 前言 今天是算法营的第27天,希望自己能够坚持下来! 今日任务: ● 贪心算法理论基础 ● 455.…

idea全局替换显示不全(ctrl+shift+R)

修改一下idea的配置就行 idea的默认显示条数为100,可以修改成10000

新版2024AndroidStudio项目目录结构拆分

如题 下载了最新版的android studio 发现目录结构和以前不一样 自动帮你合并了 如何层层抽丝剥茧呢 按照一下步骤即可解决问题!

vue el-table 数据变化后,高度渲染问题

场景:el-table设置了height属性,但是切换查询条件后再次点击查询重新获取data时,el-table渲染的高度会有问题,滚动区域变矮了。 解决办法:使用doLayout方法‌,在表格数据渲染后调用doLayout方法可以重新布局…