(七)趣学设计模式 之 适配器模式!

目录
- 一、 啥是适配器模式?
- 二、 为什么要用适配器模式?
- 三、 适配器模式的实现方式
- 1. 类适配器模式(继承插座 👨👩👧👦)
- 2. 对象适配器模式(插座转换器 🔌)
- 3. 接口适配器模式(万能插座 🗜️)
- 四、 三种适配器的对比
- 五、 适配器模式的优缺点
- 六、 适配器模式的应用场景
- 七、 总结
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解代理模式请看: (六)趣学设计模式 之 代理模式!
这篇文章带你详细认识一下设计模式中的适配器模式
一、 啥是适配器模式?
想象一下,你买了一个新的电器 💡,但是插头和家里的插座不匹配 😫,怎么办? 这时候就需要一个插座转换器 🔌,把电器的插头转换成家里的插座可以使用的类型 💡。
适配器模式,就是用来解决接口不兼容的问题! 它可以将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 🤝。
简单来说,就是把不兼容的接口转换成兼容的接口!
- 你想使用一个类,但是它的接口和你需要的接口不一样: 就像你想用一个旧的类库,但是它的接口和你的代码不兼容 😫!
- 你想让两个接口不兼容的类一起工作: 就像你想让一个美国的插头和一个中国的插座一起工作 🔌!
- 你想重用一些现有的类,但是它们的接口不符合你的要求: 就像你想用一个旧的算法,但是它的输入输出格式和你的代码不兼容 😫!
二、 为什么要用适配器模式?
用适配器模式,好处多多 👍:
- 提高类的复用性: 可以将一些现有的类适配成新的接口,方便重用 ♻️!
- 提高系统的灵活性: 可以动态地选择不同的适配器,使得系统更加灵活 🤸!
- 符合开闭原则: 可以在不修改现有代码的情况下,增加新的适配器,扩展功能 🆕!
- 解耦: 将客户端和目标类解耦,降低系统的耦合度 🔗!
三、 适配器模式的实现方式
适配器模式主要分为三种:
- 类适配器模式: 通过继承来实现适配,就像继承了插座的类 👨👩👧👦!
- 对象适配器模式: 通过组合来实现适配,就像用一个插座转换器 🔌!
- 接口适配器模式: 通过实现一个抽象类来实现适配,就像万能插座 🗜️!
1. 类适配器模式(继承插座 👨👩👧👦)
类适配器模式,通过继承来实现适配,就像继承了插座的类,拥有了插座的功能 🔌!
案例:电压适配器(经典案例 ⚡)
假设你有一个 220V 的电源 🔌,但是你需要给一个 5V 的设备充电 📱,怎么办? 这时候就需要一个电压适配器,把 220V 的电压转换成 5V 的电压 ⚡!
代码示例:
// 目标接口:5V 电压
public interface Voltage5V {int output5V(); // 输出 5V 电压
}// 需要适配的类:220V 电压
public class Voltage220V {public int output220V() {int src = 220;System.out.println("我是220V电压");return src;}
}// 适配器类:电压适配器
public class VoltageAdapter extends Voltage220V implements Voltage5V {@Overridepublic int output5V() {// 获取 220V 电压int srcV = output220V();// 转换成 5V 电压int dstV = srcV / 44;return dstV;}
}// 客户端
public class Client {public static void main(String[] args) {VoltageAdapter adapter = new VoltageAdapter(); // 创建适配器对象int voltage = adapter.output5V(); // 获取 5V 电压System.out.println("输出电压为:" + voltage + "V"); // 输出电压}
}
分析:
Voltage5V是目标接口,客户端需要使用 5V 电压。Voltage220V是需要适配的类,它只能输出 220V 电压。VoltageAdapter是适配器类,它继承了Voltage220V类,并实现了Voltage5V接口,将 220V 电压转换成 5V 电压。
输出结果:
我是220V电压
输出电压为:5V
2. 对象适配器模式(插座转换器 🔌)
对象适配器模式,通过组合来实现适配,就像用一个插座转换器,把电器的插头转换成家里的插座可以使用的类型 🔌!
案例:还是电压适配器(对象版⚡)
还是上面的电压适配器的例子,但是这次我们使用对象适配器模式来实现 🚀!
代码示例:
// 目标接口:5V 电压
public interface Voltage5V {int output5V(); // 输出 5V 电压
}// 需要适配的类:220V 电压
public class Voltage220V {public int output220V() {int src = 220;System.out.println("我是220V电压");return src;}
}// 适配器类:电压适配器
public class VoltageAdapter implements Voltage5V {private Voltage220V voltage220V; // 组合 220V 电压对象public VoltageAdapter(Voltage220V voltage220V) {this.voltage220V = voltage220V;}@Overridepublic int output5V() {// 获取 220V 电压int srcV = voltage220V.output220V();// 转换成 5V 电压int dstV = srcV / 44;return dstV;}
}// 客户端
public class Client {public static void main(String[] args) {Voltage220V voltage220V = new Voltage220V(); // 创建 220V 电压对象VoltageAdapter adapter = new VoltageAdapter(voltage220V); // 创建适配器对象int voltage = adapter.output5V(); // 获取 5V 电压System.out.println("输出电压为:" + voltage + "V"); // 输出电压}
}
分析:
Voltage5V是目标接口,客户端需要使用 5V 电压。Voltage220V是需要适配的类,它只能输出 220V 电压。VoltageAdapter是适配器类,它组合了Voltage220V类,并实现了Voltage5V接口,将 220V 电压转换成 5V 电压。
输出结果:
我是220V电压
输出电压为:5V
3. 接口适配器模式(万能插座 🗜️)
接口适配器模式,通过实现一个抽象类来实现适配,就像万能插座,可以兼容各种类型的插头 🗜️!
案例:USB 接口适配器(万能接口 💻)
假设你有一个 USB 设备 💾,但是你的电脑只有 Type-C 接口 💻,怎么办? 这时候就需要一个 USB 接口适配器,把 USB 接口转换成 Type-C 接口 💻!
代码示例:
// 目标接口:USB 接口
public interface Usb {void read(); // 读取数据void write(); // 写入数据void connect(); // 连接设备void disconnect(); // 断开连接
}// 抽象适配器类:USB 适配器
public abstract class UsbAdapter implements Usb {@Overridepublic void read() {// 默认实现,可以不实现}@Overridepublic void write() {// 默认实现,可以不实现}@Overridepublic void connect() {// 默认实现,可以不实现}@Overridepublic void disconnect() {// 默认实现,可以不实现}
}// 需要适配的类:Type-C 设备
public class TypeCDevice extends UsbAdapter {@Overridepublic void read() {System.out.println("Type-C 设备读取数据");}@Overridepublic void write() {System.out.println("Type-C 设备写入数据");}
}// 客户端
public class Client {public static void main(String[] args) {TypeCDevice typeCDevice = new TypeCDevice(); // 创建 Type-C 设备对象typeCDevice.connect(); // 连接设备typeCDevice.read(); // 读取数据typeCDevice.write(); // 写入数据typeCDevice.disconnect(); // 断开连接}
}
分析:
Usb是目标接口,客户端需要使用 USB 接口。UsbAdapter是抽象适配器类,它实现了Usb接口,但是提供了默认实现,子类可以选择性地实现需要的方法。TypeCDevice是需要适配的类,它继承了UsbAdapter类,并实现了read和write方法,实现了 USB 接口的功能。
输出结果:
Type-C 设备读取数据
Type-C 设备写入数据
四、 三种适配器的对比
| 特性 | 类适配器模式 | 对象适配器模式 | 接口适配器模式 |
|---|---|---|---|
| 实现方式 | 继承 | 组合 | 抽象类 |
| 优点 | 简单易用 | 灵活,可以适配多个类 | 可以选择性地实现接口方法 |
| 缺点 | 只能适配一个类,耦合度较高 | 需要持有目标类的对象,增加了对象的数量 | 需要定义抽象类,增加了类的数量 |
| 适用场景 | 目标类接口比较稳定,不需要经常修改 | 需要适配多个类,或者目标类接口经常修改 | 只需要使用接口中的部分方法 |
五、 适配器模式的优缺点
优点:
- 提高类的复用性 ♻️!
- 提高系统的灵活性 🤸!
- 符合开闭原则 🆕!
- 解耦 🔗!
缺点:
- 增加了系统的复杂度 😫!
- 可能会降低性能 🐌!
六、 适配器模式的应用场景
- 接口转换: 将一个类的接口转换成客户希望的另外一个接口 🔌!
- 数据转换: 将一种格式的数据转换成另外一种格式的数据 🗂️!
- 遗留系统集成: 将新的系统和旧的系统集成在一起 🤝!
- 第三方库集成: 将第三方库集成到你的项目中 📚!
七、 总结
- 适配器模式就像插座转换器,让不兼容的接口也能愉快玩耍! 🔌
- 主要分为类适配器模式、对象适配器模式和接口适配器模式三种! 🤸
- 优点是提高类的复用性、提高系统的灵活性、符合开闭原则、解耦! 👍
- 缺点是增加复杂度、可能降低性能! 👎
- 适用于需要解决接口不兼容的问题的场景! 🎯
希望这篇文章能让你彻底理解适配器模式! 💯 祝你学习愉快! 😄
相关文章:
(七)趣学设计模式 之 适配器模式!
目录 一、 啥是适配器模式?二、 为什么要用适配器模式?三、 适配器模式的实现方式1. 类适配器模式(继承插座 👨👩👧👦)2. 对象适配器模式(插座转换器 🔌…...
DeepSeek 细节之 MoE
DeepSeek 细节之 MoE DeepSeek 团队通过引入 MoE(Mixture of Experts,混合专家) 机制,以“分而治之”的思想,在模型容量与推理成本之间找到了精妙的平衡点,其中的技术实现和细节值得剖思 Transformer 演变…...
【Linux-网络】从逻辑寻址到物理传输:解构IP协议与ARP协议的跨层协作
🎬 个人主页:谁在夜里看海. 📖 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长,行则将至 目录 📚前言 📖 IP地址的组成 🔖IPv4 🔖IPv6 📚…...
毕业离校管理系统的开发与需求分析
在当今信息化的时代背景下,高校的毕业生离校管理工作也逐渐向数字化转型。为了提高工作效率,减少人为错误,增强信息透明度,毕业离校管理系统应运而生。该系统旨在为学校提供一个高效、准确的毕业生离校管理平台,从而提…...
【NLP 24、实践 ⑤ 计算Bert模型中的参数数量】
以前不甘心,总想争个对错,现在不会了 人心各有所愿,没有道理可讲 —— 25.1.18 计算Bert模型结构中的参数数量 BertModel.from_pretrained():用于从预训练模型目录或 Hugging Face 模型库加载 BERT 模型的权重及配置。 参数名称…...
一、Spring框架系统化学习路径
系统化的Spring框架学习路径 第1阶段:基础知识准备 Java基础 核心概念:面向对象、异常处理、集合框架、多线程等。JVM基础:内存模型、垃圾回收机制。 Maven或Gradle Maven:创建项目、依赖管理、生命周期。Gradle:基本…...
Midscene.js - AI驱动,轻松实现UI自动化
UI自动化测试一直是软件测试中的一项重要任务,而随着AI技术的快速发展,自动化测试的能力也在不断提升。如何让UI自动化更智能、精准、灵活?Midscene.js作为一款AI驱动的UI自动化测试工具,正逐步改变着传统自动化测试的面貌。你是不…...
(九)Mapbox GL JS 中 Marker 图层的使用详解
什么是 Marker? 在 Mapbox GL JS 中,Marker(标记) 是一个可视化元素,用于在地图上标记特定的地理位置。它可以是一个默认的图标、自定义的图像,或者任何 HTML 元素。Marker 不仅能显示位置,还能…...
2k1000LA 使能 nand.
背景 : 默认的 发货的镜像 确实 是识别不了 nand 的。 ------------------------------------------------------------------------------------------ 但是 我之前 已经写好了文档,因此 拷贝到线上。 1 首先我要使能这几个。 在menuconfig 中使能一下。...
Junit+Mock
base project <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.11</version><relativePath/></parent><dependencies><!--添加mysql依…...
maven编译出错,javac: ��Ч��Ŀ�귢�а�: 17
1、异常信息 javac: ��Ч��Ŀ�귢�а�: 17 ��: javac <options> <source files> -help �����г&a…...
Vue使用Three.js加载glb (gltf) 文件模型及实现简单的选中高亮、测距、测面积
安装: # three.jsnpm install --save three 附中文网: 5. gltf不同文件形式(.glb) | Three.js中文网 附官网: 安装 – three.js docs 完整代码(简易demo): <template><div class"siteInspe…...
<el-table>右侧有空白列解决办法
问题如图: 解决办法:.box 为本页面最外层的class名,保证各个页面样式不会互相污染。 .box::v-deep .el-table th.gutter {display: none;width: 0}.box ::v-deep.el-table colgroup col[namegutter] {display: none;width: 0;}.box::v-deep …...
Linux网络 网络层
IP 协议 协议头格式 4 位版本号(version): 指定 IP 协议的版本, 对于 IPv4 来说, 就是 4. 4 位头部长度(header length): IP 头部的长度是多少个 32bit, 也就是 4 字节,4bit 表示最大的数字是 15, 因此 IP 头部最大长度是 60 字节. 8 位服务类型(Type Of Service):…...
系统讨论Qt的并发编程——逻辑上下文的分类
目录 前言 首先,讨论Qt里常见的三种上下文 同一线程的串行执行 同一线程的异步执行 多线程的执行 moveToThread办法 前言 笔者最近看了一个具备一定启发性质的Qt教程,在这里,笔者打算整理一下自己的笔记。分享在这里. 首先,…...
《Linux Shell 脚本深度探索:原理与高效编程》
1. 基本结构 Shebang 行 #!/bin/bash # Shebang 行指定了脚本使用的解释器。 /bin/bash 表示使用 Bash 解释器执行脚本。 注释 # 这是注释,不会被执行 2. 变量 定义变量 variable_namevalue # 不需要加 $ 来定义变量。 # 变量名不能包含空格或特殊字符。 访…...
深入剖析:基于红黑树实现自定义 map 和 set 容器
🌟 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。🌟 在 C 标准模板库(STL)的大家庭里,map和set可是超级重要的关联容器成员呢😎&#x…...
在大数据项目中如何设计和优化数据模型
在大数据项目中,设计和优化数据模型是一个涉及多个步骤和维度的复杂过程。以下是我通常采取的方法: 一、数据模型设计 明确业务需求: 深入了解项目的业务场景和目标,明确数据模型需要解决的具体问题。与业务团队紧密合作…...
JavaScript querySelector()、querySelectorAll() CSS选择器解析(DOM元素选择)
文章目录 基于querySelector系列方法的CSS选择器深度解析一、方法概述二、基础选择器类型1. 类型选择器2. ID选择器3. 类选择器4. 属性选择器 三、组合选择器1. 后代组合器2. 子元素组合器3. 相邻兄弟组合器4. 通用兄弟组合器 四、伪类与伪元素1. 结构伪类2. 状态伪类3. 内容伪…...
Linux系统中处理子进程的终止问题
1. 理解子进程终止的机制 在Unix/Linux系统中,当子进程终止时,会向父进程发送一个SIGCHLD信号。父进程需要捕捉这个信号,并通过调用wait()或waitpid()等函数来回收子进程的资源。这一过程被称为“回收僵尸进程”。 如果父进程没有及时调用w…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
