(七)趣学设计模式 之 适配器模式!
目录
- 一、 啥是适配器模式?
- 二、 为什么要用适配器模式?
- 三、 适配器模式的实现方式
- 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…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...