当前位置: 首页 > news >正文

设计模式之适配器模式:软件世界的桥梁建筑师

一、什么是适配器模式

    适配器模式(Adapter Pattern)是一种结构型设计模式(Structural Pattern),通过将类的接口转换为客户期望的另一个接口,适配器可以让不兼容的两个类一起协同工作。其核心思想是通过一个中间的“适配器”类,将一个类的接口转换成客户端所期待的另一种接口形式,从而使得原本因接口不兼容而不能一起工作的类能够协同工作。就像是在现实生活中,国际旅行中常用的电源转换器,就是将不同国家的插座标准转换为你的电子设备所支持的充电接口,使设备得以顺利充电。

二、适配器模式的结构

    适配器模式通常包含以下几个主要角色:

  1. 目标接口(Target):这是客户端所期待的接口,即客户端通过此接口来调用所需的业务逻辑。

  2. 适配者(Adaptee):需要适配的类或接口,通常其现有的接口与客户端所需的接口不兼容。

  3. 适配器(Adapter):这是适配器模式的核心,它继承适配者或者持有一个适配者的引用,并通过实现目标接口,将适配者的接口转换为客户端所期望的接口。

三、适配器模式的分类

    根据适配器如何适配适配者,适配器模式可以分为两种类型:类适配器模式和对象适配器模式

1. 类适配器模式

    类适配器通过实现目标接口的同时继承适配者的方式,来实现在内部使用适配者的方法来实现目标接口的的方法:

2. 对象适配器模式

    对象适配器模式则是通过组合的方式来实现接口的适配。适配器类持有一个适配者的引用,并通过该引用来调用源角色的方法,从而实现目标接口的方法。

四、适配器模式的应用场景

    适配器模式广泛应用于各种软件开发场景中,尤其是当面临不同系统、不同库或不同版本之间的接口不兼容问题时,适配器模式往往能够提供优雅的解决方案。以下是一些典型的应用场景:

  1. 旧系统迁移:在将旧系统迁移到新系统时,新系统可能不支持旧系统的某些接口或方法。此时,可以通过适配器模式将旧系统的接口适配为新系统所需的接口,从而保持旧系统功能的可用性。

  2. 第三方库集成:在集成第三方库时,如果该库的接口与我们的系统接口不兼容,可以通过适配器模式来封装第三方库的接口,使其符合我们的系统架构和接口规范。

  3. 接口升级:在软件系统的演进过程中,有时需要对接口进行升级或重构,但升级后的接口可能与旧客户端不兼容。此时,可以通过适配器模式为旧客户端提供一个兼容层,使它们能够继续访问系统而不必立即进行更新。

  4. 多平台支持:在开发跨平台应用程序时,不同平台可能提供不同的API接口。通过适配器模式,可以将各个平台的API适配为统一的接口,从而简化开发工作和代码维护。

五、适配器模式示例

    为了更直观地理解适配器模式,以下通过一个简单的示例来说明其实现过程。

     假设我们有一个音频播放器系统,该系统支持多种音频格式的播放,但现在我们需要接入一个新的音频设备,该设备只支持MP3格式的音频。然而,我们的音频库中存在一些非MP3格式的音频文件(如WAV格式),我们需要将这些非MP3格式的音频文件转换为MP3格式后才能在该设备上播放。

1. 定义目标接口

    首先,假设存在一个目标接口AudioPlayer,表示音频播放器的功能接口。

public interface AudioPlayer {void play(String audioType, String fileName);
}

2. 定义适配者

    另外,存在一个适配者Mp3Player,它代表了一个只支持MP3格式的播放器。

public class Mp3Player {public void playMp3(String fileName) {System.out.println("Playing mp3 file. Name: " + fileName);}
}

    注意:这里Mp3Player并没有直接提供play方法,而是提供了针对特定格式的播放方法,如playMp3。

3. 创建适配器类

    现在,我们需要创建一个适配器类AudioAdapter,它实现了AudioPlayer接口,并持有一个Mp3Player的实例,以便将非MP3格式的音频文件转换为MP3格式(在这个例子中,为了简化,我们假设转换逻辑已经内置在AudioAdapter中,实际上可能需要外部转换工具或服务)。

    然而,为了保持示例的简洁性和集中讨论适配器模式的核心思想,我们将省略实际的转换逻辑,而是直接调用相应的播放方法,并输出一个假设的转换过程。

public class AudioAdapter implements AudioPlayer {private final Mp3Player mp3Player;
​public AudioAdapter(Mp3Player mp3Player) {this.mp3Player = mp3Player;}
​@Overridepublic void play(String audioType, String fileName) {if ("wma".equalsIgnoreCase(audioType)) {// 假设这里进行了wma到MP3的转换System.out.println("Converting wma to mp3 format...");} else if ("wav".equalsIgnoreCase(audioType)) {// 假设这里进行了wav到MP3的转换System.out.println("Converting wav to mp3 format...");}mp3Player.playMp3(fileName);}
}

    请注意,上述代码中的play方法通过检查audioType参数来确定要播放的音频格式,并假设进行了一些格式转换。这里的关键点是适配器类AudioAdapter如何将一个不直接支持的接口(在这个例子中是play方法,其期望接收音频类型和文件名)适配为另一个接口(Mp3Player中的playMp3方法)。

4. 使用适配器

    最后,我们可以创建一个测试类来模拟使用这个适配器。

public class AudioPlayerTest {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioAdapter(new Mp3Player());audioPlayer.play("mp3", "music.mp3");audioPlayer.play("wma", "music.wma");audioPlayer.play("wav", "music.wav");}
}

5. 运行结果

    在上面的例子中,我们创建了一个AudioPlayer类型的对象,但实际上它是一个AudioAdapter的实例,该实例内部封装了一个Mp3Player对象。通过AudioAdapter,我们能够以AudioPlayer接口期望的方式(即调用play方法并传入音频类型和文件名)来播放非MP3格式的音频文件,尽管AdvancedAudioPlayer本身并不支持这种调用方式。

相关文章:

设计模式之适配器模式:软件世界的桥梁建筑师

一、什么是适配器模式 适配器模式(Adapter Pattern)是一种结构型设计模式(Structural Pattern),通过将类的接口转换为客户期望的另一个接口,适配器可以让不兼容的两个类一起协同工作。其核心思想是通过一个…...

Java 入门指南:Java 并发编程 —— Fork/Join 框架 实现任务的拆分与合并

Fork/Join Fork/Join 是Java并发编程中的一个框架,用于解决大型任务的并行执行问题。它于 Java 7中引入,旨在简化对多核处理器上可并行执行任务的开发。 Fork/Join 框架基于分治(divide and conquer)的设计思想。它将大型任务划…...

token过期时间分平台(web和app)设置方法

token分平台设置方法 本文介绍了Spring下的登录和鉴权机制的主要方法以及 token认证的主要流程,并介绍在spring中web端和APP端设置不同token过期时间的实现方法。主要基于SpringBootspringSecurityJWT框架实现。 一、应用场景 同一系统的跨平台操作,基于…...

[000-01-008].Seata案例应用

业务说明:这里我们创建三个服务,一个订单服务,一个库存服务,一个账户服务。当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品的库存;再通过远程调用账户服务来…...

超详细!!!electron-vite-vue开发桌面应用之创建新窗口以及主进程和子进程的通信监听(十二)

云风网 云风笔记 云风知识库 一、新建打开窗口 1、在electron/main.ts中加入主进程打开窗口逻辑代码 import { ipcMain } from "electron"; ipcMain.handle("open-win", (_, arg) > {const childWindow new BrowserWindow({webPreferences: {preloa…...

java编辑器——IntelliJ IDEA

java编辑器有两种选择——IntelliJ IDEA和VsCode。其中IntelliJ IDEA现在是企业用的比较多的,是专门为java设计的,而VsCode则是通过插件来实现Java编辑的。 1.IntelliJ IDEA 官网下载链接:https://www.jetbrains.com/idea/ 注意选择社区版…...

经验笔记:SSL证书

SSL证书经验笔记 1. 什么是SSL证书? SSL(Secure Sockets Layer)证书是一种数字证书,用于在客户端(如浏览器)和服务器之间建立加密连接,以确保数据传输的安全性。随着互联网的发展,…...

设计模式之装饰器模式:让对象功能扩展更优雅的艺术

一、什么是装饰器模式 装饰器模式(Decorator Pattern)是一种结构型设计模式(Structural Pattern),它允许用户通过一种灵活的方式来动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比使用…...

Anchor Alignment Metric来优化目标检测的标签分配和损失函数。

文章目录 背景假设情况任务和目标TaskAligned方法的应用1. **计算Anchor Alignment Metric**2. **动态样本分配**3. **调整损失函数** 示例总结 背景 假设我们在进行目标检测任务,并且使用了YOLOv8模型。我们希望通过TaskAligned方法来优化Anchor与目标的匹配程度&…...

C++---由优先级队列认识仿函数

文章目录 一、优先级队列是什么? 二、如何使用优先级队列 1、优先级队列容器用法 2、为什么容器本身无序? 三、什么是仿函数? 1. 什么是仿函数? 2. 仿函数的优势 四、仿函数如何使用? 1、重载operator()函数 2、运用第…...

Client访问Server访问慢的原因

1. 网络层面的问题 网络延迟:客户端与服务器之间的地理距离较远(跨ISP、路径次优),导致高网络延迟(如高 RTT 值)。使用 ping 或 traceroute 工具可以帮助定位网络延迟的来源 - mtr: 结合了ping和traceroute功能&#…...

用RPC Performance Inspector 优化你的区块链

目录 什么是RPC? RPC Performance Inspector 是做什么的? 为什么需要这个工具? 如何使用它? 适合谁用? 如何使用? 什么是RPC? RPC Performance Inspector 是一个专门用于测试和分析RPC性能…...

linux如何查看内存条是ddr几代

在 Linux 系统中,可以通过以下几种方法查看内存条的类型和代数(如 DDR3、DDR4 等): 1. 使用 dmidecode 命令 dmidecode 是一个工具,它可以从系统的 DMI 表(也称为 SMBIOS 表)中提取硬件信息&a…...

LeetCode 3153.所有数对中数位差之和:计数

【LetMeFly】3153.所有数对中数位差之和:计数 力扣题目链接:https://leetcode.cn/problems/sum-of-digit-differences-of-all-pairs/ 车尔尼有一个数组 nums ,它只包含 正 整数,所有正整数的数位长度都 相同 。 两个整数的 数位…...

Spring Boot 整合 Sentinel 实现流量控制

在微服务架构中,流量控制是保障系统稳定性和高可用性的关键技术之一。阿里巴巴开源的 Sentinel 是一款面向分布式系统的流量防护组件,旨在从流量控制、熔断降级、系统负载保护等多个维度保障服务的稳定性。本文将详细介绍如何在 Spring Boot 项目中整合 …...

Elasticsearch倒排索引

什么是倒排索引 倒排索引(Inverted Index)是一种将文档中的每个单词映射到包含该单词的文档列表上的数据结构 倒排索引的构建过程 文档1: “我爱吃苹果” 文档2: “我爱吃香蕉” 文档3: “我喜欢苹果和香蕉” 文档分词:将文档中的文本内容…...

速盾:ddos常用防御方法是什么?

DDoS攻击是一种通过向网络资源发送大量请求或大流量数据来使其过载的攻击手段。为了应对这种攻击,常用的防御方法可以分为三个层次:流量清洗、服务器升级和高防CDN。 流量清洗是一种基础的防御手段,它通过过滤和识别恶意流量来阻止DDoS攻击。…...

二分算法入门(简单题)

习题1 704. 二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], targ…...

在使用React Hooks中,如何避免状态更新时的性能问题?

在React Hooks中避免状态更新时的性能问题,可以采取以下一些最佳实践: 避免不必要的状态更新: 使用React.memo、useMemo、和useCallback来避免组件或其子组件进行不必要的渲染。 使用useMemo: 对于基于状态或props的复杂计算&…...

Pytest插件pytest-selenium-让自动化测试更简洁

在现代Web应用的开发中,自动化测试成为确保网站质量的重要手段之一。而Pytest插件 pytest-selenium 则为开发者提供了简单而强大的工具,以便于使用Python进行Web应用的自动化测试。本文将深入介绍 pytest-selenium 插件的基本用法和实际案例,…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

基础测试工具使用经验

背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【单片机期末】单片机系统设计

主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...