设计模式17-适配模式
设计模式17-适配模式
- 动机
- 定义与结构
- C++代码推导
- 总结
- 应用
- 具体应用示例
动机
- 在软件系统中由于应用环境的变化常常需要将一些现存的对象。放到新的环境中去应用。但是新环境要求的接口是这些现存对象所不满足的。
- 那么这种情况下如何应对这种迁移的变化?如何既能利用现有对象的良好实现用了满足新的应用环境所要求的接口。
适配器模式是解决两个接口不兼容的问题。通过适配器模式,我们可以将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式主要用于以下场景:
- 当你想使用一个已经存在的类,但它的接口不符合你的需求时。
- 当你想创建一个可以重用的类,该类可以和不兼容的接口协同工作时。
- 当你想使用一些现有的子类,但是不能进行子类化来匹配接口时,因为这会导致每个子类需要调整。
定义与结构
定义
- 适配器模式将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适配器模式包含以下主要角色:
- 目标(Target)接口:定义客户所需的接口。
- 适配者(Adaptee)类:定义一个已经存在的接口,这个接口需要适配。
- 适配器(Adapter)类:将适配者接口转换成目标接口,使得客户端可以通过目标接口与适配者进行通信。
适配器模式有两种实现方式:
- 类适配器(Class Adapter):使用多重继承实现适配。
- 对象适配器(Object Adapter):使用组合实现适配。
类适配器模式UML图:
---------------- ---------------- -----------------
| Target |<---| Adapter |<| Adaptee |
|----------------| |----------------| |---------------|
|+request() | |+request() | |+specificRequest|
----------------- ----------------- ---------------
对象适配器模式UML图:
---------------- ---------------- ----------------
| Target |<---| Adapter |<| Adaptee |
|----------------| |----------------| |----------------|
|+request() | |+request() | |+specificRequest|
----------------- | -adaptee: Adaptee| ------------------------------------
C++代码推导
类适配器模式:
#include <iostream>// 目标接口
class Target {
public:virtual void request() = 0;virtual ~Target() = default;
};// 适配者类
class Adaptee {
public:void specificRequest() {std::cout << "Adaptee specific request." << std::endl;}
};// 类适配器
class Adapter : public Target, private Adaptee {
public:void request() override {specificRequest();}
};// 客户端代码
int main() {Target* target = new Adapter();target->request(); // 调用适配器的方法delete target;return 0;
}
对象适配器模式:
#include <iostream>// 目标接口
class Target {
public:virtual void request() = 0;virtual ~Target() = default;
};// 适配者类
class Adaptee {
public:void specificRequest() {std::cout << "Adaptee specific request." << std::endl;}
};// 对象适配器
class Adapter : public Target {
private:Adaptee* adaptee;public:Adapter(Adaptee* adaptee) : adaptee(adaptee) {}void request() override {adaptee->specificRequest();}
};// 客户端代码
int main() {Adaptee* adaptee = new Adaptee();Target* target = new Adapter(adaptee);target->request(); // 调用适配器的方法delete target;delete adaptee;return 0;
}
总结
-
适配器模式主要应用于希望服用一些现存的类可用于复用环境要求不一致的情况。在遗留代码复用嗯类库迁移等方面非常常用。
-
世界模式书中定义了两种适配器模式的实现结构:对象适配器和类适配器。但是类适配器采用多继承的实现方式。一般不推荐使用。对象适配器采用对象组合的方式更符合松耦合的设计理念。
-
适配器模式可以实现的非常灵活不必拘泥于设计模式书中定义的两种结构。例如完全可以将适配器模式中的现存对象作为新的接口方法参数,来达到适配的目的。
优点:
- 单一职责原则:可以将接口或数据转换代码从原始类中分离出来。
- 开闭原则:无需修改客户端代码即可引入新的适配器类。
- 灵活性高:类适配器使用多重继承,可以适配多个适配者类。对象适配器使用组合,可以在运行时对适配者进行替换。
缺点:
- 类适配器的缺点:
- 不支持适配多个适配者类,因为C++不支持多继承多个实现类。
- 破坏了Adaptee类和Adapter类的独立性,因为适配器继承自适配者。
- 对象适配器的缺点:
- 在某些情况下,可能需要多次调用适配者的方法,导致性能开销较大。
应用
适配器模式在实际应用中非常广泛,常见的应用场景包括:
- 使用遗留代码库:当你想使用一个现有的类,但它的接口不符合你的需求时,可以使用适配器模式进行适配。
- 与第三方库集成:当你想使用第三方库,但它的接口与你的代码不兼容时,可以使用适配器模式进行适配。
- 处理多种接口:当你需要创建一个可以与多个不兼容接口进行交互的类时,可以使用适配器模式进行适配。
具体应用示例
以下是一个适配器模式的具体应用示例:将一个旧的日志系统适配到新的日志系统中。
旧日志系统:
#include <iostream>class OldLogger {
public:void oldLog(const std::string& message) {std::cout << "OldLogger: " << message << std::endl;}
};
新日志系统接口:
class NewLogger {
public:virtual void log(const std::string& message) = 0;virtual ~NewLogger() = default;
};
适配器类:
class LoggerAdapter : public NewLogger {
private:OldLogger* oldLogger;public:LoggerAdapter(OldLogger* logger) : oldLogger(logger) {}void log(const std::string& message) override {oldLogger->oldLog(message);}
};
客户端代码:
int main() {OldLogger* oldLogger = new OldLogger();NewLogger* logger = new LoggerAdapter(oldLogger);logger->log("This is a log message."); // 使用适配器进行日志记录delete logger;delete oldLogger;return 0;
}
通过上述示例,我们将旧的日志系统适配到新的日志系统接口中,使得客户端代码可以无缝使用旧的日志系统,同时保持代码的灵活性和可维护性。这就是适配器模式在实际开发中的典型应用。
相关文章:
设计模式17-适配模式
设计模式17-适配模式 动机定义与结构C代码推导总结应用具体应用示例 动机 在软件系统中由于应用环境的变化常常需要将一些现存的对象。放到新的环境中去应用。但是新环境要求的接口是这些现存对象所不满足的。那么这种情况下如何应对这种迁移的变化?如何既能利用现…...
react ant Input defaultValue={value}设置了value值以后,但是defalult没有赋值上,输入框也没有显示
在 React 中,defaultValue 是一个非受控属性,而 value 是一个受控属性。这两个属性都可以用于设置 Input 组件的值,但是它们的工作方式有所不同。 value:这是一个受控属性,意味着输入框的值由 React 状态控制。每当状态…...
大模型开发如何把一段文字变成一组token?
在大模型开发中,将一段文字变成一组token通常称为"tokenization"(分词)。这是自然语言处理中的一个关键步骤,主要是将连续的文本划分成离散的单元(token),这些单元可以是单词、子词或…...
【MSYS】Windows Terminal 集成
Windows Terminal 集成 MSYS2安装在默认位置C:\msys64打开Windows Terminal打开JSON配置文件文件。 添加如下配置: "profiles": {"defaults": {},"list": [{"guid": "{71160544-14d8-4194-af25-d05feeac7233}"…...
Python酷库之旅-第三方库Pandas(056)
目录 一、用法精讲 211、pandas.Series.truncate方法 211-1、语法 211-2、参数 211-3、功能 211-4、返回值 211-5、说明 211-6、用法 211-6-1、数据准备 211-6-2、代码示例 211-6-3、结果输出 212、pandas.Series.where方法 212-1、语法 212-2、参数 212-3、功能…...
ZBrush入门使用介绍——4、笔刷选项说明
大家好,我是阿赵。 这次来看看ZBrush的笔刷的选项用法。 一、选择笔刷 点击笔刷,可以打开笔刷选择面板。 在最上面的Quick Pick,有最近使用过的笔刷,可以快速的选择。下面有很多可以选择的笔刷。但由于笔刷太多,…...
Java每日一练,技术成长不间断
目录 题目1.下列关于继承的哪项叙述是正确的?2.Java的跨平台特性是指它的源代码可以在多个平台运行。()3.以下 _____ 不是 Object 类的方法4.以下代码:5.下面哪个流类不属于面向字符的流()总结 题目 选自牛…...
传知代码-上下位关系自动检测方法(论文复现)
代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 概述 本文复现论文 Hearst patterns revisited: Automatic hypernym detection from large text corpora[1] 提出的文本中上位词检测方法。 在自然语言处理中,上下位关系(Is-a Relations…...
从零开始的MicroPython(二) GPIO及代码应用
上一篇:http://t.csdnimg.cn/mg2Qt 文章目录 ESP32(NodeMCU-32S)简介引脚注意事项 类与对象的概念MicroPython的GPIO使用文档解释machine.PinPin.irq 点灯 ESP32(NodeMCU-32S) 简介 NodeMCU-32S 是安信可基于 ESP32-32S 模组所设计的核心开发板。该开发板延续了 N…...
嵌入式day15
数组指针 能够指向整个数组 一维数组: &a,考察a的数据类型 int(*p)[10]:表示一个指向长度为10的一维整型数组的指针 二维数组: 指向函数的指针 函数的函数名,即为函数的入口地址&#x…...
【电池管理系统(BMS)-01】 | 电池管理系统简介,动力电池和储能电池区别
🎩 欢迎来到技术探索的奇幻世界👨💻 📜 个人主页:一伦明悦-CSDN博客 ✍🏻 作者简介: C软件开发、Python机器学习爱好者 🗣️ 互动与支持:💬评论 &…...
C++ STL partial_sum 用法
一:功能 计算部分和,即遍历序列中每个元素,计算前 i 个元素的累加和,并将结果存在 i 的位置上。 二:用法 #include <iostream> #include <vector> #include <numeric>int main() {std::vector<…...
诚宜开张圣听不应妄自菲薄
拾人牙慧孜孜不倦 青山依旧在几度夕阳红朝闻道夕死可矣 青山依旧在几度夕阳红 安能以血补天我计不成乃天命也臣本布衣躬耕南阳大丈夫宁死不辱尔要试我宝剑是否锋利吗又待怎样休教天下人负我竖子不足与谋皇天不佑天下英雄唯使君与操尔青光殷殷其灿如炎备不量力欲申大义于天下我…...
Vue3 加载条(LoadingBar)
效果如下图:在线预览 APIs LoadingBar 参数说明类型默认值必传containerClass加载条容器的类名stringundefinedfalsecontainerStyle加载条容器的样式CSSProperties{}falseloadingBarSize加载条大小,单位 pxnumber2falsecolorLoading加载中颜色string‘…...
《CSS创意项目实战指南》:点亮网页,从实战中掌握CSS的无限创意
CSS创意项目实战指南 在数字时代,网页不仅是信息的载体,更是艺术与技术的融合体。通过CSS,你可以将平凡的网页转变为引人入胜的视觉盛宴,让用户体验跃升至全新高度。《CSS创意项目实战指南》正是这样一本引领你探索CSS无限可能的…...
[FBCTF2019]RCEService (PCRE回溯绕过和%a0换行绕过)
json格式输入ls出现index.php 这道题原本是给了源码的,BUUCTF没给 源码: <?phpputenv(PATH/home/rceservice/jail);if (isset($_REQUEST[cmd])) {$json $_REQUEST[cmd];if (!is_string($json)) {echo Hacking attempt detected<br/><br/…...
vue3后台管理系统 vue3+vite+pinia+element-plus+axios上
前言 项目安装与启动 使用vite作为项目脚手架 # pnpm pnpm create vite my-vue-app --template vue安装相应依赖 # sass pnpm i sass # vue-router pnpm i vue-router # element-plus pnpm i element-plus # element-plus/icon pnpm i element-plus/icons-vue安装element-…...
Mysql的事务隔离级别实现原理
一、事务隔离级别 mysql支持四种事务隔离级别: 读未提交:一个事务可以读取到另一个事务还未提交的数据;读已提交:一个事务可以读取到另一个事务已经提交的数据;可重复读:同一个事务中,无论读取…...
计算机体系结构:缓存一致性ESI
集中式缓存处理器结构(SMP) 不同核访问存储器时间相同。 分布式缓存处理器结构(NUMA) 共享存储器按模块分散在各处理器附近,处理器访问本地存储器和远程存储器的延迟不同,共享数据可进入处理器私有高速缓存…...
log4j2漏洞练习(未完成)
log4j2 是Apache的一个java日志框架,我们借助它进行日志相关操作管理,然而在2021年末log4j2爆出了远程代码执行漏洞,属于严重等级的漏洞。apache log4j通过定义每一条日志信息的级别能够更加细致地控制日志生成地过程,受影响的版本…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
