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

目录
- 一、 啥是适配器模式?
- 二、 为什么要用适配器模式?
- 三、 适配器模式的实现方式
- 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…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
