Spring框架之适配器模式 (Adapter Pattern)

适配器模式(Adapter Pattern)详解

适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要作用是将一个类的接口转换成客户端期望的另一个接口,使原本由于接口不兼容而无法一起工作的类可以协同工作。适配器模式通常被用来修复已有代码的兼容性问题,尤其是在重用现有类时避免大规模修改代码。

1. 适配器模式的定义

1.1 什么是适配器模式?

适配器模式将 不兼容的接口 进行适配,使得原本不兼容的类能够在一起工作。它就像生活中的电源适配器,可以让不同国家的电器设备在本国的电网环境下正常工作。

1.2 适配器模式的特点
  • 转换接口:将一个类的接口转换为客户端所期望的另一个接口。
  • 兼容性:解决接口不兼容的问题,让原本无法协作的类能够协同工作。
  • 封装旧接口:适配器模式常用于将旧系统的接口封装起来,以便与新系统兼容。

2. 适配器模式的结构

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

  1. Target(目标接口)
    • 客户端期望使用的接口。
  2. Adaptee(被适配者)
    • 需要适配的类,其接口与目标接口不兼容。
  3. Adapter(适配器)
    • 将被适配者的接口转换为目标接口的一个包装类。
  4. Client(客户端)
    • 使用目标接口的类。
类图
    +-------------+|   Target    |<--------------------++-------------+                     || + request() |                     |+-------------+                     |^                           ||                           |+--------------+          +----------------+|   Adapter    |--------->|   Adaptee      |+--------------+          +----------------+| + request()  |          | + specificRequest() |+--------------+          +----------------+

3. 适配器模式的分类

适配器模式有两种主要实现方式:

  1. 类适配器(Class Adapter)
    • 使用继承来实现适配器。适配器类继承自 AdapteeTarget
    • 由于 Java 只支持单继承,因此在 Java 中类适配器使用场景较少。
  2. 对象适配器(Object Adapter)
    • 使用组合来实现适配器。适配器类持有一个 Adaptee 对象的引用。
    • 这种方式更加灵活,是推荐的实现方式。

4. 适配器模式的实现

为了更好地理解适配器模式,我们使用一个简单的示例来演示其工作原理。假设我们有一个 AudioPlayer 类,它只能播放 .mp3 文件,现在我们希望它也能播放 .mp4.vlc 文件。

4.1 Java 示例代码:对象适配器
// 目标接口
interface MediaPlayer {void play(String audioType, String fileName);
}// 被适配者类(支持 VLC 播放)
class VlcPlayer {public void playVlc(String fileName) {System.out.println("播放 VLC 文件: " + fileName);}
}// 被适配者类(支持 MP4 播放)
class Mp4Player {public void playMp4(String fileName) {System.out.println("播放 MP4 文件: " + fileName);}
}// 适配器类
class MediaAdapter implements MediaPlayer {private VlcPlayer vlcPlayer;private Mp4Player mp4Player;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {vlcPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {mp4Player = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {vlcPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {mp4Player.playMp4(fileName);}}
}// 具体目标类
class AudioPlayer implements MediaPlayer {private MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("播放 MP3 文件: " + fileName);} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("不支持的文件格式: " + audioType);}}
}// 测试客户端
public class AdapterPatternDemo {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "歌曲.mp3");audioPlayer.play("mp4", "电影.mp4");audioPlayer.play("vlc", "动画.vlc");audioPlayer.play("avi", "短片.avi");}
}

输出结果

播放 MP3 文件: 歌曲.mp3
播放 MP4 文件: 电影.mp4
播放 VLC 文件: 动画.vlc
不支持的文件格式: avi

5. 适配器模式的应用场景

适配器模式适合以下场景:

  1. 希望复用一些现有的类,但是类的接口不符合当前系统的需求。
  2. 想要封装一些旧系统的类,以便在新系统中使用。
  3. 使用第三方库,而其接口与项目中定义的接口不兼容。
  4. 希望创建一个可复用的类,使其能够与不相关或不可预见的类协同工作。

6. 适配器模式的优缺点

6.1 优点
  • 提高类的复用性:通过适配器模式,现有类可以与其他类进行协作,而无需修改原始类的代码。
  • 提高类的灵活性和扩展性:通过引入适配器类,可以在不修改现有代码的情况下增加新功能。
  • 解耦目标类与被适配者类:适配器将目标类和被适配者类隔离开来,实现了解耦。
6.2 缺点
  • 增加系统复杂度:引入适配器后,系统会增加额外的适配器类,导致复杂度增加。
  • 不易理解:尤其是系统中存在大量适配器时,可能会导致代码难以理解和维护。
  • 类适配器的实现受限于继承:在 Java 中,类适配器受限于单继承的特性,因此更推荐使用对象适配器。

7. 适配器模式的扩展

7.1 双向适配器
  • 适配器模式可以实现双向适配,即适配器不仅能够将被适配者转化为目标接口,也能将目标接口转化为被适配者接口。
7.2 缺省适配器(Default Adapter)
  • 适用于接口中有多个方法时,想要简化接口的实现。通常通过创建一个抽象类,该抽象类提供这些方法的默认实现,具体类只需重写需要的方法。

8. 适配器模式的实际应用

  1. Java I/O 类库
    • Java 的 InputStreamReaderOutputStreamWriter 就是典型的适配器模式,用于在字节流和字符流之间进行适配。
  2. 数据库连接
    • JDBC 中的 DriverManager 使用适配器模式来适配不同的数据库驱动程序。
  3. Spring 框架
    • Spring 的 HandlerAdapter 适配器用于将不同类型的请求处理器(如 ControllerHttpRequestHandler)适配成统一的处理方式。

9. 总结

适配器模式是一种非常有用的设计模式,尤其是在需要与现有系统集成时。通过适配器模式,可以有效地复用现有代码,同时保持系统的灵活性和扩展性。

  • 优点:提高复用性、解耦、增加灵活性。
  • 缺点:增加复杂度、不易理解。
  • 适用场景:复用现有类、封装旧系统、使用第三方库。

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

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

相关文章

记录日志中logback和log4j2不能共存的问题

本文章记录设置两个日志时候&#xff0c;控制台直接报错 标黄处就是错误原因&#xff1a;1. SLF4J(W)&#xff1a;类路径包含多个SLF4J提供程序。 SLF4J(W)&#xff1a;找到提供程序[org.apache.logging.slf4j. net]。 SLF4J(W)&#xff1a;找到提供程序[ch.qos.log .classi…

【PGCCC】Postgresql Toast 原理

前言 上篇博客讲述了 postgresql 如何存储变长数据&#xff0c;它的应用主要是在 toast 。Toast 在存储大型数据时&#xff0c;会将它存储在单独的表中&#xff08;称为 toast 表&#xff09;。因为 postgresql 的 tuple&#xff08;行数据&#xff09;是存在在 Page 中的&…

C指针创建三维数组

定义的时候变量的位置就是最后一个星号的位置 int*** matrix3d_int(int nz, int nrh, int nch) {int*** matrix (int***)malloc(nz * sizeof(int**));for (int z 0; z < nz; z) {matrix[z] (int**)malloc(nrh * sizeof(int*));for (int y 0; y < nrh; y) {matrix[z][…

window下安装rust 及 vscode配置

安装 安装mingw64 &#xff08;c语言环境 选择posix-ucrt&#xff09; ucrt:通用c运行时库配置mingw64/bin的路径到环境变量中在cmd窗口中输入命令 "gcc -v" 4. 下载Rust安装程序 安装 Rust - Rust 程序设计语言 5. 配置rustup和cargo目录 &#xff08;cargo是包管…

wordpress搭建主题可配置json

网站首页展示 在线访问链接 http://dahua.bloggo.chat/ 配置json文件 我使用的是argon主题&#xff0c;你需要先安装好主题&#xff0c;然后可以导入我的json文件一键配置。 需要json界面配置文件的&#xff0c;可以在评论区回复&#xff0c;看见评论我会私发给你。~

基于表格滚动截屏(表格全部展开,没有滚动条)

import html2canvasPro from html2canvas // 截图&#xff0c;平辅表格 async function resetAgSize() {const allColumns gridApi.value.getColumns()let totalColumnWidth 0let totalColumnHeight 0// 遍历每一个行节点gridApi.value.forEachNode((rowNode) > {totalCo…

运行springBlade项目历程

框架选择 官网地址&#xff1a;https://bladex.cn 使用手册&#xff1a;https://www.kancloud.cn/smallchill/blade 常见问题&#xff1a;https://sns.bladex.cn/article-14966.html 问答社区&#xff1a;https://sns.bladex.cn 环境配置 存在jdk8的情况下安装jdk17 jdk17gi…

文件上传漏洞--理论

什么是文件上传漏洞&#xff1f; Web应用允许用户上传文件&#xff0c;但是没有对上传的文件进行严格的过滤和检测&#xff0c;导致网站执行了文件中包含的恶意代码。 漏洞的基本利用方式是&#xff1a; 成功上传包含恶意代码的文件&#xff0c;并在服务端成功执行该文件。 …

物联网(RFID)全景:被装信息化监控应用与挑战

一、被装物联网信息化建设的动因 信息化改革在20世纪80年代中期启航&#xff0c;旨在提升被装保障的效率。随着时间的推移&#xff0c;硬件的广泛运用和软件的快速迭代&#xff0c;装备业务在规划、制造、分发以及战时支援等核心环节&#xff0c;已经与信息系统深度融合&#x…

解决C盘空间不足的三种方案

方案一&#xff1a;网上盛传的C盘磁盘碎片整理&#x1f9e9;&#xff08;原理&#xff1a;将分散的文件片段整理到相邻的磁盘区域&#xff0c;减少文件的碎片化程度&#xff09;(效果不明显) 方案二&#xff1a;把其他盘的空间给C盘 &#x1f4bd;&#xff08;效果显著&#xf…

[项目代码] YOLOv5 铁路工人安全帽安全背心识别 [目标检测]

YOLOv5是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv5具有更高的…

有什么初学算法的书籍推荐?

对于初学算法的读者&#xff0c;以下是一些值得推荐的书籍&#xff1a; 1、算法超简单&#xff1a;趣味游戏带你轻松入门与实践 作者&#xff1a;童晶 著 推荐理由&#xff1a;本书把趣味游戏应用于算法教学&#xff0c;提升读者的学习兴趣&#xff0c;并通过可视化的图解和动…

卸载一直显示在运行的应用

GX_work2: 打开文件 CtrlA全选卸载&#xff0c;他会显示有正在运行的软件点击跳过 然后打开被跳过的文件&#xff0c;CtrlA全选卸载 可能还是会显示有正在运行的软件点击跳过 直到出现.exe应用&#xff0c;最后打开任务管理器搜索此.exe应用&#xff0c;关闭它 最后完全卸载…

问:MySQL主从同步的机制梳理?

MySQL主从复制是一种数据库复制技术&#xff0c;通过将一个MySQL数据库服务器&#xff08;主节点&#xff09;的数据复制到一个或多个其他MySQL数据库服务器&#xff08;从节点&#xff09;&#xff0c;实现数据的自动同步。这种技术不仅提高了数据的可用性&#xff0c;还能通过…

基于BILSTM及其他RNN序列模型的人名分类器

数据集Kaggle链接 NameNationalLanguage | Kaggle 数据集分布: 第一列为人名,第二列为国家标签 代码开源地址 Kaggle代码链接 https://www.kaggle.com/code/houjijin/name-nationality-classification Gitee码云链接 人名国籍分类 Name Nation classification: using BI…

期权懂|期权新手入门教学:期权合约有哪些要素?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 期权新手入门教学&#xff1a;期权合约有哪些要素&#xff1f; 期权合约&#xff1a;是指约定买方有权在将来某一时间以特定价格买入或卖出约定标的物的标准化或非标准化合约。期…

Oracle OCP认证考试考点详解082系列16

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 76. 第76题&#xff1a; 题目 解析及答案&#xff1a; 以下哪三项活动会被记录在数据库的警报日志中&#xff1f; A. 块损坏错误 数据库…

【Linux篇】面试——用户和组、文件类型、权限、进程

目录 一、权限管理 1. 用户和组 &#xff08;1&#xff09;相关概念 &#xff08;2&#xff09;用户命令 ① useradd&#xff08;添加新的用户账号&#xff09; ② userdel&#xff08;删除帐号&#xff09; ③ usermod&#xff08;修改帐号&#xff09; ④ passwd&…

论文阅读《机器人状态估计中的李群》

目录 摘要1 介绍2 微李理论2.1 李群2.2 group actions2.3 正切空间和李代数 摘要 李群是一个古老的数学抽象对象&#xff0c;可以追溯到19世纪&#xff0c;当时数学家 Sophus Lie奠定了连续变换群理论的基础。多年后&#xff0c;它的影响已经蔓延到科学和技术的各个领域。在机…

智能零售柜商品识别

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…