设计模式七:适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的接口能够协同工作。
适配器模式涉及角色:
- 目标接口(Target Interface):目标接口是客户端所期望的接口,适配器将源接口转换为目标接口以满足客户端的需求。
- 适配器(Adapter):适配器是一个实现了目标接口的类,它持有一个源接口的引用。适配器通过调用源接口的方法来完成客户端的请求,并根据需要进行数据转换和适配。
- 源接口(Adaptee Interface):源接口是需要被适配的接口,它定义了适配器需要转换成目标接口的方法。。
适配器模式的使用场景
- 兼容性问题:当有两个或多个类之间存在兼容性问题,无法直接进行交互时,可以使用适配器模式。适配器将不兼容的接口转换成目标接口,使得这些类能够协同工作
- 类库的使用:当需要使用一个已有的类库,但其接口与当前系统的需要不符时,可以使用适配器来适配该类库的接口,以便于在当前系统中使用。
- 组件复用:当希望复用已有的组件,并且这些组件的接口与当前系统的需求不一致时,可以使用适配器模式来对这些组件进行适配,以便在当前系统中复用它们。
- 系统扩展性:当系统需要扩展以支持新的功能或接口时,可以使用适配器模式。通过适配器,能够方便地添加新的适配器来支持新的功能或接口,而无需修改现有的代码。
适配器模式提供了一种解决兼容性问题和接口不一致问题的灵活方式,可以有效地将现有的代码与新的需求或组件进行集成。
适配器模式的java代码实例
// 目标接口
interface MediaPlayer {void play(String audioType, String fileName);
}// 具体目标类
class AudioPlayer implements MediaPlayer {public void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing mp3 file: " + fileName);} else {System.out.println("Invalid media type");}}
}// 高级媒体播放器接口
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}// 具体高级媒体播放器类
class VlcPlayer implements AdvancedMediaPlayer {public void playVlc(String fileName) {System.out.println("Playing vlc file: " + fileName);}public void playMp4(String fileName) {// 不支持,不做任何操作}
}class Mp4Player implements AdvancedMediaPlayer {public void playVlc(String fileName) {// 不支持,不做任何操作}public void playMp4(String fileName) {System.out.println("Playing mp4 file: " + fileName);}
}// 适配器类
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMediaPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMediaPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMediaPlayer = new Mp4Player();}}public void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMediaPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMediaPlayer.playMp4(fileName);} else {System.out.println("Invalid media type");}}
}// 客户端代码
public class Main {public static void main(String[] args) {MediaPlayer mediaPlayer = new AudioPlayer();mediaPlayer.play("mp3", "song.mp3"); // 直接播放MP3文件mediaPlayer = new MediaAdapter("vlc");mediaPlayer.play("vlc", "movie.vlc"); // 使用适配器播放VLC文件mediaPlayer = new MediaAdapter("mp4");mediaPlayer.play("mp4", "video.mp4"); // 使用适配器播放MP4文件}
}
在上面的示例中,MediaPlayer 是目标接口,AudioPlayer 是具体目标类,它可以直接播放 mp3 文件。AdvancedMediaPlayer 是高级媒体播放器接口,VlcPlayer 和 Mp4Player 是具体的高级媒体播放器类。
MediaAdapter 是适配器类,它实现了目标接口 MediaPlayer,并在内部封装了一个高级媒体播放器对象。根据传入的音频类型,它选择合适的高级媒体播放器来播放相应的文件。
在客户端代码中,我们首先创建一个 AudioPlayer 对象,然后直接使用它来播放 mp3 文件。接着,我们再使用适配器将 AudioPlayer 转换成 MediaPlayer 对象,并使用适配器对象来播放 vlc 文件和 mp4 文件。这样,即使目标接口和高级媒体播放器之间存在兼容性问题,我们也可以通过适配器将它们协同工作起来。
适配器模式的优缺点
适配器模式用于解决接口不兼容的问题。它将不同接口的对象进行转换,使其能够协同工作。适配器模式有以下优缺点:
优点:
- 解决接口不兼容问题:适配器模式能够处理不同接口之间的兼容性问题,使得不兼容的类能够协同工作。
- 重用现有功能:适配器模式可以重用已经存在的功能实现。通过适配器模式,我们可以使用已有的类来实现新的接口需求,而无需修改现有代码。
- 扩展性良好:通过适配器模式,可以轻松地添加新的适配器类来支持更多的对象和接口。
缺点:
- 增加复杂性:引入适配器会增加系统的复杂性和代码量,因为需要额外的适配器类来转换接口。
- 运行时效率损失:由于适配器会在客户端代码和适配者之间增加一层间接调用,可能会导致运行时的效率损失。
总体来说,适配器模式是在接口不兼容的情况下使用的一种很有用的设计模式。它帮助我们解决了不同接口之间的兼容性问题,并能够重用现有代码。然而,适配器模式也会引入一些复杂性,需要权衡其使用时带来的好处和额外的成本。
相关文章:
设计模式七:适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的接口能够协同工作。 适配器模式涉及角色: 目标接口(Target Interface):…...
数据结构---队列
(一)队列之基础补充 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。 —— 百科 「队列 Queue」是一种…...
chatGPT在软件测试中应用方式有哪些?
ChatGPT可以在软件测试中以以下方式应用: 1. 自动化对话测试:ChatGPT可以用于自动化对话测试,模拟用户与软件系统进行实时对话。它可以扮演用户的角色,向系统发送各种类型的指令和请求,并验证系统的响应是否符合预期。…...

chatgpt 接口使用(一)
使用api实现功能 参考链接:https://platform.openai.com/examples 安装库: pip3 install openai 例如: import os import openaiopenai.api_key os.getenv("OPENAI_API_KEY") response openai.ChatCompletion.create(model&q…...

【个人笔记】Linux 服务管理两种方式service和systemctl
service命令与systemctl 命令 service 命令与传统的 SysVinit 和 Upstart 初始化系统相关。较早期的 Linux 发行版(如早期的 Ubuntu、Red Hat 等)使用了这些初始化系统。service 命令用于启动、停止、重启和查询系统服务的状态。虽然许多现代 Linux 发行…...

HCIP中期考试实验
考试需求 1、该拓扑为公司网络,其中包括公司总部、公司分部以及公司骨干网,不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名,并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中,运行OSPF协议或者BGP…...
【WebRTC---源码篇】(二十二)WebRTC的混音处理
音频混音主力 音频混音主体主要通过(重采样) + (混音)为主 音频重采样 内容实现是在webrtc::voe中实现的,下面来对重采样全流程逐一分析 。 void RemixAndResample(const AudioFrame& src_frame,//源音频数据帧PushResampler<int16_t>* resampler,//重采样对…...

MTK system_server 卡死导致手机重启案例分析
和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一、MTK AEE Log分析工具二、AEE Log分析流程三、system_server 卡死案例分析及解决 本文主要针对 Exception Type: system_server_watchdog , system_…...
加强 Kubernetes 能力:利用 CRD 定义多版本资源的实现方式
姚灿武,Rancher 中国研发工程师,拥有 7 年云计算领域经验,热衷开源技术,在云原生相关技术领域拥有丰富的开发和实践经验。 CRD,即自定义资源定义(Custom Resource Definition),是 Ku…...

区块链应用 DApp 开发需要掌握的技能
文章目录 前言为什么要开发 DAppDApp 的优势DApp 应用范围DApp 开发者技能 前言 前面区块链系列的文章中介绍了区块链技术、智能合约、web3js,Solidity 编程语言,在开发者的角度就是要基于这些知识在Web3时代去开发一个 DApp(去中心化应用程…...

关于新版本selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘等问题
由于一段时间没有使用Selenium,当再次使用时发现之前写的Selenium元素定位的代码运行之后会报错,发现是Selenium更新到新版本(4.x版本)后,以前的一些常用的代码的语法发生了改变,当然如果没有更新过或是下载…...
c++通过自然语言处理技术分析语音信号音高
对于语音信号的音高分析,可以使用基频提取技术。基频是指一个声音周期的重复率,也就是一个声音波形中最长的周期。 通常情况下,人的声音基频范围是85Hz到255Hz。根据语音信号的基频可以推断出其音高。 C中可以使用数字信号处理库或语音处理库…...

[pymc3][python]pymc3安装后测试代码2
测试环境: pymc33.11.2 代码: import numpy as np import pymc3 as pm import matplotlib.pyplot as pltif __name__ __main__:# 生成随机数据np.random.seed(123)x np.linspace(0, 1, 100)y 0.5 * x np.random.normal(0, 0.1, size100)# 定义概率…...

Go语言time库,时间和日期相关的操作方法
time库 用于处理时间、日期和时区的核心库。在实际开发中,常常需要与时间打交道,例如记录日志、处理时间差、计算时间间隔等等。因此,掌握time库的使用方法对于Go开发者来说非常重要。 在Go语言中,时间表示为time.Time类型&…...

JVM总结笔记
JVM JVM是什么?JVM 的主要组成部分JVM工作流程JVM内存模型直接内存与堆内存的区别:堆栈的区别Java会存在内存泄漏吗?简述Java垃圾回收机制垃圾收集算法轻GC(Minor GC)和重GC(Full GC)新生代gc流程JVM优化与JVM调优 JVM是什么? JVM是Java Virtual Mach…...
C++ 缓存再排序,解决多线程处理后的乱序问题,不知道思路对不对[挠下巴]
C 缓存再排序,解决多线程处理后的乱序问题,不知道思路对不对[挠下巴] 使用map默认会根据key排序的原理作缓存,队列满了依次推出,抛弃掉过时的数据 #include <functional> #include <iostream> #include <map> #…...
华为数通HCIA-地址分类及子网划分
ip地址(逻辑地址) 作用:唯一标识一张网卡 特点:设备天生没有,需要人为配置,可以随时修改 格式:点分十进制 大小:32bit 组成:网络位主机位 网络位:用于标…...

Linux第七章之gdb与makefile使用
一、Linux调试器-gdb使用 1.1背景 程序的发布方式有两种,debug模式和release模式Linux gcc/g出来的二进制程序,默认是release模式要使用gdb调试,必须在源代码生成二进制程序的时候, 加上-g 选项[重要] 1.2开始使用 …...

Mycat-Balance使用指南
MyCAT Balance是一个Java NIO的高性能负载均衡器,可以替代普通的硬件的交换机或其LVS类似的复杂机制,实现MyCAT集群的负载均衡。 MyCAT Balance的配置文件在conf目录下,frontend-conf.为前端配置,包括绑定的端口等,js…...

玩转顺序表——【数据结构】
在C语言学习中,我们经常会遇见增删查改等一系列操作,而这些操作全都与线性表关联,没有线性表将会对这些操作完成的十分艰难!那今天就让我们来了解一下顺序表如何增删查改!!! 目录 1.线性表 2…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...