设计模式--适配器模式(Adapter Pattern)

一、什么是适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一个接口。适配器模式主要用于解决不兼容接口之间的问题,使得原本由于接口不匹配而无法一起工作的类能够协同工作。

适配器模式涉及以下几个核心角色:

  1. 目标接口(Target Interface):客户端所期望的接口,适配器将现有的接口转换成这个目标接口。
  2. 适配器(Adapter):适配器类实现了目标接口,同时持有一个需要被适配的对象。适配器通过适配被适配对象的接口,使其能够符合目标接口的要求。
  3. 被适配对象(Adaptee):需要被适配的现有类。它可能具有与目标接口不同的接口。

适配器模式的目标是使不兼容的接口能够一起工作,同时也可以在一些情况下用来重用现有的类,而无需修改其源代码。

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

  1. 类适配器模式:使用继承的方式将适配器与被适配对象结合起来,使适配器可以调用被适配对象的方法并实现目标接口。
  2. 对象适配器模式:使用组合的方式将适配器与被适配对象结合起来,使适配器通过调用被适配对象的方法来实现目标接口。

适配器模式在现实世界中的例子是,将电子设备从一个插头类型适配到另一个插头类型,以使其能够连接到不同的电源插座。

适配器模式提供了一种方式来处理不同接口之间的集成问题,使得系统中不同部分可以协同工作,从而提高了代码的灵活性和可维护性。

二、类适配器模式的代码样例

以下是一个使用C++实现类适配器模式的简单示例:

#include <iostream>// 目标接口
class TargetInterface {
public:virtual void request() = 0;
};// 被适配的类
class Adaptee {
public:void specificRequest() {std::cout << "Adaptee's specificRequest called." << std::endl;}
};// 适配器类(类适配器)
class Adapter : public TargetInterface, public Adaptee {
public:void request() override {specificRequest();}
};int main() {TargetInterface* target = new Adapter();target->request();delete target;return 0;
}

在这个示例中,我们有一个目标接口 TargetInterface,它定义了客户端期望的接口。然后有一个被适配的类 Adaptee,它具有与目标接口不同的接口。最后,我们创建了一个适配器类 Adapter,它继承了目标接口 TargetInterface 并继承了被适配类 Adaptee。适配器类的 request 方法通过调用被适配类的 specificRequest 方法来实现目标接口。

在主函数中,我们通过创建适配器对象,并将其视为目标接口的实例,从而可以调用 request 方法来实现被适配类的功能。

这个示例展示了类适配器模式的基本概念,通过继承来适配被适配的类的接口,使其能够符合目标接口的要求。

三、对象适配器模式的代码样例

以下是一个使用C++实现对象适配器模式的简单示例:

#include <iostream>// 目标接口
class TargetInterface {
public:virtual void request() = 0;
};// 被适配的类
class Adaptee {
public:void specificRequest() {std::cout << "Adaptee's specificRequest called." << std::endl;}
};// 适配器类(对象适配器)
class Adapter : public TargetInterface {
public:Adapter(Adaptee* adaptee) : adaptee(adaptee) {}void request() override {adaptee->specificRequest();}private:Adaptee* adaptee;
};int main() {Adaptee* adaptee = new Adaptee();TargetInterface* target = new Adapter(adaptee);target->request();delete target;delete adaptee;return 0;
}

在这个示例中,我们依然有一个目标接口 TargetInterface,一个被适配的类 Adaptee,以及一个适配器类 Adapter。与之前不同的是,适配器类不再继承被适配的类,而是在构造函数中持有被适配类的实例。

适配器类的 request 方法通过调用被适配类的 specificRequest 方法来实现目标接口。

在主函数中,我们先创建了一个被适配类的实例 adaptee,然后将其传递给适配器类 Adapter 的构造函数来创建适配器对象。然后,我们通过适配器对象调用 request 方法来实现被适配类的功能。

这个示例展示了对象适配器模式的基本概念,通过组合和持有被适配的对象来适配其接口,从而使其能够符合目标接口的要求。

四、类适配器模式和对象适配器模式的区别

类适配器模式和对象适配器模式是适配器模式的两种不同实现方式,它们的区别主要体现在适配器与被适配对象之间的关系以及实现方式上。

类适配器模式:

  1. 关系:在类适配器模式中,适配器类通过继承被适配的类来实现适配。适配器同时拥有目标接口和被适配类的功能,因此可以通过调用被适配类的方法来实现目标接口。
  2. 实现方式:适配器类继承被适配类,可以直接访问被适配类的方法和属性,但也可能需要重新实现一些方法来适配目标接口。
  3. 结构复杂性:类适配器模式的结构相对较简单,但可能会受到被适配类的限制,因为继承只能应用于具有合适继承关系的类。

对象适配器模式:

  1. 关系:在对象适配器模式中,适配器类通过组合持有一个被适配的对象实例。适配器持有被适配对象的引用,通过调用被适配对象的方法来实现目标接口。
  2. 实现方式:适配器类在自己的方法中调用被适配对象的方法,实现了目标接口。适配器还可以在自己的方法中添加一些额外的逻辑。
  3. 灵活性:对象适配器模式更灵活,可以适配多个不同的被适配对象,而不受继承关系的限制。

选择哪种适配器模式:

  • 选择类适配器模式还是对象适配器模式取决于设计需求和被适配对象的特性。如果被适配对象是一个类,且希望通过继承来复用其功能,可以选择类适配器模式。如果被适配对象是一个接口或一个无法继承的类,或者希望适配多个不同的被适配对象,可以选择对象适配器模式。

总之,两种适配器模式都有各自的优势和用途,根据具体情况选择合适的实现方式。

五、使用适配器模式需要注意的问题

在使用适配器模式时,需要注意以下几个问题:

  1. 接口一致性:适配器模式的目的是将不兼容的接口转换成兼容的接口,但在适配过程中需要确保目标接口满足客户端的需求,否则可能会导致功能不正常或错误。
  2. 覆盖问题:在类适配器模式中,适配器类继承了被适配类的方法和属性。如果被适配类的方法与目标接口的方法同名,适配器可能需要覆盖被适配类的方法,以实现目标接口的需求。这可能导致子类方法的覆盖问题。
  3. 被适配对象的状态:在适配过程中,被适配对象的状态可能会受到影响。在适配器中调用被适配对象的方法时,需要确保对象的状态不会出现意外的变化。
  4. 灵活性和复用性:适配器模式可以在不同的场景中复用现有的类,但在适配过程中可能会引入一些特定的逻辑,这可能会影响到代码的灵活性和复用性。
  5. 过多的适配器:过度使用适配器模式可能会导致系统中存在大量的适配器类,从而增加代码的复杂性。需要根据实际情况权衡是否使用适配器模式。
  6. 性能问题:适配器模式可能会引入额外的开销,特别是在适配器的方法中涉及转换和逻辑时。需要在性能要求高的情况下进行评估和优化。

总之,适配器模式是一种用于解决接口不匹配问题的有用工具,但在使用时需要仔细考虑接口一致性、状态维护、代码复用等问题,以确保适配器能够正确地将不兼容的接口转换成兼容的接口。

在这里插入图片描述

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

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

相关文章

Android 回退键监听

方法1&#xff1a;回调方法onBackPressed String LOG_TAG"TAG";Overridepublic void onBackPressed() {// super.onBackPressed();//注释掉这行,back键不退出activityLog.i(LOG_TAG, "onBackPressed");} 这个方法可以阻止用户点击后退键来退出程序。 一般…

numpy高级函数之where和extract函数

1 numpy.where() 函数返回输入数组中满足给定条件的元素的索引 ---------------------------------------------------- 代码&#xff1a; n1np.random.randint(10,20,10) n2np.where(n1>15) 结果&#xff1a; [17 15 19 15 12 10 16 11 15 13] #原始数组 (array([…

leetcode:338. 比特位计数(python3解法)

难度&#xff1a;简单 给你一个整数 n &#xff0c;对于 0 < i < n 中的每个 i &#xff0c;计算其二进制表示中 1 的个数 &#xff0c;返回一个长度为 n 1 的数组 ans 作为答案。 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;[0,1,1] 解释&#xff1a; 0…

飞天使-vim简单使用技巧

此文是记录技巧使用&#xff0c;如果想节约时间&#xff0c;可以直接看最后一个章节 vim 的介绍 vim号称编辑器之神&#xff0c;唯快不破&#xff0c;可扩展&#xff0c;各种插件满天飞。 vi 1991 vim 1.14 vim四种模式 普通模式: 移动光标&#xff0c; 删除文本&#xff0c…

百度Apollo:自动驾驶技术的未来应用之路

文章目录 前言一、城市交通二、出行体验三、环境保护四、未来前景总结 前言 随着科技的不断进步&#xff0c;自动驾驶技术正逐渐成为现实&#xff0c;颠覆着我们的出行方式。作为中国领先的自动驾驶平台&#xff0c;百度Apollo以其卓越的技术和开放的合作精神&#xff0c;正在…

购物车的删除功能 getters action mutation

购物车的删除功能应该写在getters action还是 mutation里面&#xff0c;为什么 购物车的删除功能应该写在action和mutation中&#xff0c;而不是getters中。这是因为getters主要用于获取和计算状态的派生属性&#xff0c;而不用于进行状态的修改。 getters&#xff1a;getters…

RedisDesktopManager(redis客户端,可输入用户名密码)

RedisDesktopManager&#xff08;redis客户端&#xff0c;可输入用户名密码&#xff09; Redis桌面管理器&#xff08;又名RDM&#xff09; - 是一个用于Windows&#xff0c;Linux和MacOS的快速开源Redis数据库管理应用程序。可以使用url连接或账号密码。 redis设置账号密码后…

嵌入式Linux开发教程汇总

一、文档 野火&#xff1a;https://doc.embedfire.com/products/link/zh/latest/linux/index.html正点原子&#xff1a;http://47.111.11.73/docs/boards/arm-linux/index.html百问网&#xff1a;http://download.100ask.net/books/Linux/ELADCM1/index.html 二、视频 百问网…

[论文阅读笔记26]Tracking Everything Everywhere All at Once

论文地址: 论文 代码地址: 代码 这是一篇效果极好的像素级跟踪的文章, 发表在ICCV2023, 可以非常好的应对遮挡等情形, 其根本的方法在于将2D点投影到一个伪3D(quasi-3D)空间, 然后再映射回去, 就可以在其他帧中得到稳定跟踪. 这篇文章的方法不是很好理解, 代码也刚开源, 做一…

嵌入式设备应用开发(发现需求和提升价值)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 很多做技术的同学,都会陷入到技术的窠臼之中。对于如何做具体的产品、实现具体的技术,他们可能很感兴趣。但是做出来的东西做什么用,或者说是有没有竞争力,事实上他们不是很关心…

身为一个后端程序员如何快速制作后端管理系统的UI

前言 我的专业领域在后端开发上&#xff0c;前端我仅仅是熟悉&#xff0c;但是要从头开发一个前端UI界面有点难为人了。那么身为一个后端程序员我们怎么来开发后端管理系统UI界面呢&#xff1f; 方案1&#xff1a;现成的模版来套&#xff08;有一定的前端基础&#xff0c;只是…

搭建开发环境-Mac

概述 上一篇搭建开发环境-WSLUbuntu 记录了WSL 和Ubuntu 下开发环境的搭建。这一篇就说下Mac开发环境的搭建。 就像很多人误以为Mini 是专为女孩子设计的高颜值车&#xff0c;其实是一辆极其hardcore 的拉力车一样。 很多人都被Mac 那高颜值蒙蔽了&#xff0c;其实这是一台生产…

JS 动画 vs CSS 动画:究竟有何不同?

在 Web 前端开发中&#xff0c;动画是提高用户体验的关键因素之一。我们通常可以使用 JavaScript&#xff08;JS&#xff09;和 CSS 来创建动画效果。但是&#xff0c;这两者之间有哪些区别呢&#xff1f;在本文中&#xff0c;我们将深入研究 JS 动画和 CSS 动画&#xff0c;探…

基于swing的旅游管理系统java jsp旅行团信息mysql源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于swing的旅游管理系统 系统有1权限&#xff1a;管…

vue权限管理——请求和响应权限控制

1.请求头中设置token 每次请求请求头都携带token&#xff0c;没有token或者token失效后端会返回错误 axios.interceptors.request.use(configs > {let token sessionStorage.getItem("token");if (token) {configs.headers.authorization token;} } 2.拒绝非…

flask获取请求对象的get和post参数

前言 get请求参数是在URL里面的&#xff0c;post请求参数是放在请求头里面的 get请求&#xff1a; index_page.route("/get") def get():var_a request.args.get("a", "jarvis")return "request:%s,params:%s,var_a:%s" %(request…

上传镜像到阿里云的ACR

1、开通阿里云ACR 2、在ACR 中创建命名空间 3、本地安装docker 4、登录到 开通ACR&#xff0c;需要配置访问凭证 [rootmaster ~]# docker login --username***lb registry.cn-beijing.aliyuncs.com Password: 5、给镜像打标签 [rootmaster ~]# docker images REPOSITORY …

【中危】Apache XML Graphics Batik<1.17 存在SSRF漏洞 (CVE-2022-44729)

zhi.oscs1024.com​​​​​ 漏洞类型SSRF发现时间2023-08-23漏洞等级中危MPS编号MPS-2022-63578CVE编号CVE-2022-44729漏洞影响广度极小 漏洞危害 OSCS 描述Apache XML Graphics Batik 是一个开源的、用于处理可缩放矢量图形(SVG)格式图像的工具库。 受影响版本中&#xff0…

prometheus + grafana进行服务器资源监控

在性能测试中&#xff0c;服务器资源是值得关注一项内容&#xff0c;目前&#xff0c;市面上已经有很多的服务器资 源监控方法和各种不同的监控工具&#xff0c;方便在各个项目中使用。 但是&#xff0c;在性能测试中&#xff0c;究竟哪些指标值得被关注呢&#xff1f; 监控有…

Jupyter Notebook 配置根目录

注&#xff1a;本文是在 Windows 10 上配置 Jupyter Notebook 打开的默认根目录&#xff0c;Linux 同。 步骤一&#xff1a;创建 Jupyter Notebook 配置文件 使用以下命令创建 Jupyter Notebook 配置文件&#xff08;如果尚未创建&#xff09;&#xff1a; jupyter notebook …