设计模式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通过定义每一条日志信息的级别能够更加细致地控制日志生成地过程,受影响的版本…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...