【设计模式】结构型-适配器模式

前言

在软件开发中,经常会遇到需要将一个类的接口转换成另一个类的接口的情况。这可能是因为新旧系统之间的接口不兼容,或者是因为需要使用的第三方库的接口与当前系统的接口不匹配。为了解决这类问题,设计模式中的适配器模式应运而生。

一、不兼容的接口

假设场景:你购买了一台最新款的笔记本电脑,但是它只有 USB-C 接口。你有一些旧的 USB 设备,比如鼠标和键盘,它们都是标准的 USB 接口。现在的问题是,你无法直接将这些 USB 设备连接到只有 USB-C 接口的笔记本电脑上。

// 代表标准 USB 接口的类
class StandardUSB {public void connect() {System.out.println("连接标准 USB 接口");}
}// 代表 USB-C 接口的类
class USBC {public void connect() {System.out.println("连接 USB-C 接口");}
}// 客户端尝试使用标准 USB 设备连接到 USB-C 接口
public class Client {public static void main(String[] args) {StandardUSB standardUSB = new StandardUSB();USBC usbc = new USBC();// 这里会出现问题,因为我们不能直接将标准 USB 设备连接到 USB-C 接口// standardUSB.connect(); // 假设这是连接到 USB-C 接口的尝试,但实际上是不可能的// usbc.connect(); // 这是 USB-C 设备的连接,与标准 USB 设备不兼容}
}

二、适配器模式

适配器模式是一种常见的设计模式,属于结构型设计模式之一。它用于将一个类的接口转换成客户端所期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。适配器模式主要解决软件系统中存在的接口不兼容的问题。

适配器模式的特点:

  1. 兼容性提升:主要用于解决接口不兼容的问题。当需要使用的接口与现有接口不匹配时,适配器模式允许客户端通过适配器访问目标类,从而提升了系统的兼容性。
  2. 松耦合:适配器模式使得客户端与目标类之间的耦合度降低。客户端只需要针对适配器进行编程,而不需要直接与目标类交互,这样可以减少系统的依赖性。
  3. 复用性增强:适配器模式可以重用已有的类,而不需要修改其代码。通过创建适配器,可以将现有的类集成到新的环境中,从而提升代码的复用性。

三、适配器模式的核心组成部分

适配器模式的核心组成包括以下几个要素:

  1. 目标接口(Target): 目标接口是客户端所期待的接口,也是客户端代码调用的接口。适配器模式通过适配器将适配者的接口转换成目标接口,使得客户端可以统一调用目标接口来使用适配者的功能。目标接口定义了客户端需要使用的一组方法或行为。
  2. 适配者类(Adaptee): 适配者类是需要被适配的类,其接口与目标接口不兼容。适配者类通常是已经存在的、具有一定功能的类,但其接口可能与当前系统的接口要求不一致,导致无法直接被客户端使用。
  3. 适配器(Adapter): 适配器是适配器模式的核心组件,其作用是将适配者的接口转换成目标接口。适配器可以通过类适配器模式或对象适配器模式来实现。在类适配器模式中,适配器类继承适配者类,并实现目标接口,通过重写目标接口的方法来调用适配者类的方法。在对象适配器模式中,适配器类包含适配者类的实例,并实现目标接口,通过调用适配者类实例的方法来实现目标接口的方法。

在这里插入图片描述

这个类图描述了适配器模式中的核心组件之间的关系。在类图中:

  1. Target 表示目标接口,其中定义了客户端需要调用的 request() 方法。
  2. Adapter 类表示适配器,其中包含了一个私有成员 adaptee,用于持有适配者类的实例。Adapter 类实现了 Target 接口,并通过调用 Adaptee 接口的方法来实现 Target 接口的方法。
  3. Adaptee 接口表示适配者类,其中定义了适配者类具有的 specificRequest() 方法。Adapter 类与 Adaptee 接口之间的关系表示适配器通过调用适配者类的方法来实现目标接口的方法。

四、运用适配器模式

场景假设: 你有一台只有 USB-C 接口的笔记本电脑,但你需要连接标准 USB 接口的设备,如鼠标和键盘。

  1. 定义目标接口: 首先,我们定义一个目标接口 USBTarget,它包含了笔记本电脑中需要使用的 USB 连接方法。
    // 目标 USB 接口
    interface USBTarget {void connectUSB();
    }// 标准 USB 设备类
    class StandardUSBDevice {public void connectStandardUSB() {System.out.println("连接标准 USB 接口");}
    }// USB-C 接口类
    class USBCPort {public void connectUSBC() {System.out.println("连接 USB-C 接口");}
    }
    
  2. 创建适配器类: 然后,我们创建一个适配器类 USBToUSBCAdapter,该类实现了目标接口 USBTarget。
    // USB 到 USB-C 适配器类
    class USBToUSBCAdapter implements USBTarget {private StandardUSBDevice standardUSBDevice;public USBToUSBCAdapter(StandardUSBDevice standardUSBDevice) {this.standardUSBDevice = standardUSBDevice;}@Overridepublic void connectUSB() {// 适配器内部调用标准 USB 设备的连接方法standardUSBDevice.connectStandardUSB();System.out.println("通过适配器连接到 USB-C 接口");}
    }
    
  3. 调用适配器: 最后,我们在系统中使用适配器类来连接标准 USB 设备,而不是直接尝试将其插入 USB-C 接口。
    	// 客户端代码public class Client {public static void main(String[] args) {// 创建标准 USB 设备实例StandardUSBDevice standardUSB = new StandardUSBDevice();// 创建适配器实例,传入标准 USB 设备USBToUSBCAdapter adapter = new USBToUSBCAdapter(standardUSB);// 通过适配器连接设备adapter.connectUSB();}}
    

在上面的示例中:

  1. 目标(Target):这是客户端期望使用的接口。在我们的例子中,USBTarget 接口就是目标接口,它定义了笔记本电脑需要的 USB 连接方法,即 connectUSB()
  2. 适配器(Adapter):适配器实现了目标接口,并持有一个被适配者的引用。在例子中,USBToUSBCAdapter 类就是适配器,它实现了 USBTarget 接口,并在内部通过持有 StandardUSBDevice 的引用来调用正确的方法。
  3. 被适配者(Adaptee):这是已经存在的、需要被适配的类,它的接口与目标接口不兼容。在我们的例子中,StandardUSBDevice 类就是被适配者,它有一个 connectStandardUSB() 方法,这个方法与目标接口不匹配。

通过这种方式,适配器模式允许客户端通过目标接口与被适配者进行交互,即使它们的接口不直接兼容。适配器负责转换接口调用,使得客户端可以无缝地使用被适配者的功能。

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

适配器模式适用于以下几种场景:

  1. 集成新旧系统:当系统需要集成使用旧版本的接口或者已有的类库,但新系统的接口与旧系统不兼容时,适配器模式可以用来创建一个适配器,使新系统能够与旧系统进行通信。
  2. 使用第三方库:当需要使用第三方库提供的接口,但其接口与当前系统的接口不匹配时,可以使用适配器模式来创建一个适配器,以便让系统与第三方库进行集成。
  3. 系统升级:在对系统进行升级或者重构时,有时候会改变原有的接口或者类结构,而旧的客户端代码可能仍然依赖于旧接口。适配器模式可以用来在新接口和旧接口之间进行适配,使得旧的客户端代码能够继续工作。
  4. 类库复用:当系统需要重用一个已有的类库,但该类库的接口与系统所期望的接口不匹配时,可以使用适配器模式创建一个适配器,将该类库适配到系统中,从而实现代码的复用。
  5. 统一接口:当系统中存在多个类似但接口不同的类时,可以使用适配器模式创建统一的接口,使得客户端可以通过统一的接口与这些类进行交互,而不需要关心具体的实现细节。

六、小结

适配器模式是一种非常有用的设计模式,它可以帮助我们解决接口不兼容的问题,同时提升系统的灵活性和可维护性。通过适配器模式,我们可以轻松地集成不同接口的类,并使它们能够协同工作。在实际项目中,适配器模式经常被用来进行系统集成、接口转换等方面的工作,是软件开发中不可或缺的一部分。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/847859.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PB案例学习笔记】-16做一个修改系统时间的小应用

写在前面 这是PB案例学习笔记系列文章的第16篇,该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码,小凡都上传到了gite…

教师服务期内可以调动吗

作为一名还在服务期内的老师,你可能会好奇:我在服务期内能不能换个学校教书?这个问题听起来简单,但实际上答案得看具体情况。 什么是服务期呢?简单来说,就是你和学校签了合同,得在校工作满五年&…

qt dragEnterEvent dragLeaveEvent dragMoveEvent dropEvent都不响应的问题解决方案。

环境&#xff1a;vs2019qt5.14.2 坑哦。让我搞了好久。各种不执行&#xff0c;最后发现,不用vs调制&#xff0c;直接运行exe就能接收拖拽了。 记录一下,感觉是qt的bug。上代码。 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QText…

Spring使用事务的两种方式

1. 为什么需要事务&#xff1f; 前面的博客 对MySQL事务作讲解&#xff0c;事务就是将⼀组操作封装成⼀个执⾏单元&#xff08;封装到⼀起&#xff09;&#xff0c;要么全部成功&#xff0c;要么全部失败。 比如&#xff0c;现在要实现转账操作&#xff1a; 第一步&#xff…

两张图片进行分析

两张图片进行分析&#xff0c;可以拖动左边图片进行放大、缩小查看图片差异 底图 <template><div class"box_container"><section><div class"" v-for"item in imgData.imgDataVal" :key"item.id"><img :s…

Mybatis02-CRUD操作及配置解析

1、CRUD 1.namespace namespace中的包名要和Dao/Mapper 接口的包名一致&#xff01; 1个Dao接口类对应1个mapper&#xff0c;也对应1个namespace&#xff0c; 1个Dao接口中的方法对应1个namespace中一个SQL语句 2.CRUD id&#xff1a;对应的namespace接口中的方法名resul…

html+CSS+js部分基础运用14

熟悉插值{{}}的用法&#xff0c;在页面中显示下列内容。图1 插值语法的效果图 在页面中统计鼠标单机按钮的次数。【提示&#xff1a;v-on指令】&#xff0c;页面效果如下图所示&#xff1a;图2 统计效果图 3、①单击按钮可以修改黑体字。②通过调试工具vue-devtools修改黑体字。…

服务器数据恢复—服务器raid5上层zfs文件系统数据恢复案例

服务器数据恢复环境&故障&#xff1a; 一台某品牌X3650M3服务器&#xff0c;服务器中有一组raid5磁盘阵列&#xff0c;上层采用zfs文件系统。 服务器未知原因崩溃&#xff0c;工作人员排查故障后发现服务器的raid5阵列中有两块硬盘离线导致该阵列不可用&#xff0c;服务器内…

Web3.0区块链技术开发方案丨ICO与IDO代币开发

在Web3.0时代的到来下&#xff0c;区块链技术不仅改变着金融领域的格局&#xff0c;也在资金筹集和代币发行方面掀起了一场变革。初始代币发行&#xff08;ICO&#xff09;和去中心化代币发行&#xff08;IDO&#xff09;成为了项目融资的主要方式&#xff0c;其基于区块链技术…

电脑开机之后要很久才能进入系统?进入WinPE也是卡顿半天?

前言 小白最近接到了一张很奇怪的电脑维修单&#xff0c;客户说他的工作室电脑开机特别慢&#xff0c;开机之后特别卡顿&#xff0c;在使用的时候也会一卡一卡的。 这事情开始看很简单&#xff1a;估计就是电脑还是机械硬盘&#xff0c;所以开机很慢又卡顿。所以应该是把机械…

LSDFi协议赛道4大稳定币项目,以bitget钱包为例

纵览 LSDfi 生态繁荣的基石&#xff0c;LSD 稳定币赛道全解析 近期有许多建立在流动性质押通证的稳定币借贷协议开始出现在大众眼里&#xff0c;今天文章就要带大家来一一了解这些 LSDfi 协议究竟是如何争夺这块诱人的大饼。 LybraFinanceLSD 它透过抵押stETH/ETH 铸造&#…

MySQL经典练习50题(上)(解析版)

所有笔记、生活分享首发于个人博客 想要获得最佳的阅读体验&#xff08;无广告且清爽&#xff09;&#xff0c;请访问本篇笔记 MySQL经典练习50题&#xff08;上&#xff09; 创建数据库和表 -- 建 表 -- 学 生 表 CREATE TABLE Student( s_id VARCHAR(20), s_name VARCHAR(2…

Linux shell编程学习笔记57:lshw命令 获取cpu设备信息

0 前言 在Linux中&#xff0c;获取cpu信息的命令很多&#xff0c;除了我们已经研究的 cat /proc/cpuinfo、lscpu、nproc、hwinfo --cpu 命令&#xff0c;还有 lshw命令。 1 lshw命令的功能 lshw命令源自英文list hardware&#xff0c;即列出系统的硬件信息&#xff0c;这些硬…

C++之noexcept

目录 1.概述 2.noexcept作为说明符 3.noexcept作为运算符 4.传统throw与noexcept比较 5.原理剖析 6.总结 1.概述 在C中&#xff0c;noexcept是一个关键字&#xff0c;用于指定函数不会抛出异常。如果函数保证不会抛出异常&#xff0c;编译器可以进行更多优化&#xff0c;…

C语言.数据结构.单链表经典算法

数据结构.单链表经典算法 1.经典算法OJ题1&#xff1a;移除链表元素1.1题目描述&#xff1a;1.2题解&#xff1a;1.3图文解释&#xff1a; 2.经典算法OJ题2&#xff1a;反转链表2.1题目描述&#xff1a;2.2题解&#xff1a;2.3图文解释 3.经典算法OJ题3&#xff1a;合并两个有序…

编译和运行qemu-uboot-arm64单板的Armbian系统

这篇文章ARM虚拟机安装OMV-CSDN博客遗留一个启动qemu-uboot-arm64单板Armbian镜像的问题&#xff0c;使用官方下载的镜像&#xff0c;会报错&#xff1a; fatal: no kernel available .... Failed to load /vmlinuz ...... qemu-system-aarch64 -smp 8 -m 8G -machine virt …

WPF音乐播放器 零基础4个小时左右

前言&#xff1a;winfrom转wpf用久的熟手说得最多的是,转回去做winfrom难。。当时不明白。。做一个就知道了。 WPF音乐播放器 入口主程序 FontFamily"Microsoft YaHei" FontSize"12" FontWeight"ExtraLight" 居中显示WindowStartupLocation&quo…

数据结构:并查集

数据结构&#xff1a;并查集 题目描述参考代码 题目描述 输入样例 5 5 C 1 2 Q1 1 2 Q2 1 C 2 5 Q2 5输出样例 Yes 2 3参考代码 #include <iostream>using namespace std;const int N 100010;int n, m; int p[N], sz[N];int find(int x) // 返回x的祖宗节点 路径…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十六)- 微服务(6)

目录 10. Docker 10.1 Docker基本操作 10.1.1 镜像相关命令 10.1.2 容器相关命令 10.2 数据卷命令 10.2.1 常用命令 : 10.2.2 挂载数据卷 10. Docker 10.1 Docker基本操作 10.1.1 镜像相关命令 docker --help 查看docker帮助文档 docker images --help 查看docker ima…

Java中条件运算符的嵌套使用技巧总结

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…