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

Java设计模式-适配器模式

Java 设计模式——适配器模式(Adapter Pattern)

适配器模式把一个“不兼容”的接口转换成客户端所期待的接口,使得原本由于接口不匹配而无法一起工作的类可以协同工作。这种模式也叫“Wrapper”。
在 Java 生态中,大量应用(JDBC-ODBC Bridge、XML 解析器、日志门面 slf4j、Spring 的统一消息转换器等)都在使用适配器模式。

一、模式结构与角色

  1. Target(目标接口):客户端直接使用的抽象/接口。
  2. Adaptee(被适配者):已经存在的、接口不兼容的类或第三方库。
  3. Adapter(适配器):把 Adaptee 包装起来,实现 Target,完成接口转换。

有两种实现方式:

  • 类适配器(Class Adapter):使用多重继承(Java 不支持多继承,只能用继承+实现),继承 Adaptee 并实现 Target。
  • 对象适配器(Object Adapter)推荐方式,持有 Adaptee 对象的组合引用,实现 Target;松耦合、符合“组合复用原则”。

时序图(Object Adapter):

Client --> Target.request()|vAdapter|+---> adaptee.specificRequest()

二、代码示例

场景说明
老播放系统只能播放 mp3,新需求要支持 mp4/vlc,但 mp4、vlc 接口并不一样。采用适配器统一成可识别接口 MediaPlayer。

1. 定义目标接口 & 业务实体

//目标接口
public interface MediaPlayer {void play(String audioType, String fileName);
}//高级播放器接口(需要被适配)
public interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}

2. 两个具体的 Adaptee

public class VlcPlayer implements AdvancedMediaPlayer {public void playVlc(String fileName) { System.out.println("播放 vlc: " + fileName); }public void playMp4(String fileName) { /* 空实现 */ }
}public class Mp4Player implements AdvancedMediaPlayer {public void playVlc(String fileName) { /* 空实现 */ }public void playMp4(String fileName) { System.out.println("播放 mp4: " + fileName); }
}

3. 对象适配器

public class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedPlayer;public MediaAdapter(String audioType) {switch (audioType.toLowerCase()) {case "vlc": advancedPlayer = new VlcPlayer(); break;case "mp4": advancedPlayer = new Mp4Player(); break;}}@Overridepublic void play(String audioType, String fileName) {switch (audioType.toLowerCase()) {case "vlc": advancedPlayer.playVlc(fileName); break;case "mp4": advancedPlayer.playMp4(fileName); break;default: throw new IllegalArgumentException("格式不支持");}}
}

4. 客户端使用

public class AudioPlayer implements MediaPlayer {private MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if ("mp3".equalsIgnoreCase(audioType)) {// 本地支持的格式System.out.println("播放 mp3: " + fileName);} else if ("vlc".equalsIgnoreCase(audioType) || "mp4".equalsIgnoreCase(audioType)) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("不支持 " + audioType + " 格式");}}// 运行示例public static void main(String[] args) {AudioPlayer player = new AudioPlayer();player.play("mp3", "beyond.mp3");player.play("mp4", "alone.mp4");player.play("vlc", "far far away.vlc");player.play("avi", "mind me.avi"); //输出:不支持 avi 格式}
}

输出

播放 mp3: beyond.mp3
播放 mp4: alone.mp4
播放 vlc: far far away.vlc
不支持 avi 格式

三、JDK & 三方库经典用例

  1. java.util.Arrays#asList(T…):将数组对象适配成 List
  2. java.io.InputStreamReader / OutputStreamWriter:把字节流 Adaptee 适配成字符流 Target。
  3. javax.xml.bind.annotation.adapters:把 XML 日期与 java.util.Date 互相转换。
  4. Spring MVC HandlerAdapter:将不同类型的后端 Handler(普通 @Controller、Servlet、带 @ResponseBody 的方法等)适配成统一的 handle 调用。
  5. slf4j:所有桥接包(log4j-over-slf4j、jcl-over-slf4j)都是适配器,把旧日志系统接口伪装成 slf4j 接口。

四、优缺点

优势

  • 透明:客户端只依赖 Target,根本不知道 Adaptee。
  • 复用:现有类无需修改,符合“开闭原则”。
  • 灵活性:可以一次封装多个 Adaptee(见 Spring MVC)。

劣势

  • 类适配器只能适配一个具体类,且会暴露 Adaptee 的 public 方法(继承导致紧耦合)。
  • 过度使用会导致系统层次变多、不易理解。

五、何时使用

  1. 想复用某个现成类,但接口不符合需要。
  2. 希望创建一个可重用类,与若干不可预见接口的类一起工作。
  3. 需要转换多种已存在的子类接口,统一对外暴露接口时(如 Spring Adapter)。
  4. 需要桥接旧系统(遗留代码)与新系统。
http://www.xdnf.cn/news/1178551.html

相关文章:

  • Docker4-容器化企业级应用
  • 不同头会关注输入序列中不同的部分和不同维度所蕴含的信息,这里的头和嵌入维度不是对应的,仅仅是概念上的吗?
  • 调节广告adload的算法:Contextual Bandits、多臂老虎机 Policy Gradient、Q-learning
  • C++ 中打开文件的多种方式及相关流类
  • 【重学数据结构】哈希表 Hash
  • 【学习路线】JavaScript全栈开发攻略:前端到后端的完整征程
  • MySQL高可用部署
  • MySQL的底层原理--InnoDB记录存储结构
  • Mysql大数据架构设计:当表中数据超过800万时,对数据表进行分表操作,以及分页查询优化详解
  • C++扩展 --- 并发支持库(下)
  • 【YOLO系列】YOLOv4详解:模型结构、损失函数、训练方法及代码实现
  • PA333H-2K功率计:光伏行业高压测试“刚需”
  • 智慧驾驶疲劳检测算法的实时性优化
  • ARM 学习笔记(四)
  • 嵌入式软件--stm32 DAY 9 定时器
  • Springmvc的自动解管理
  • 一文说清楚Hive中常用的聚合函数[collect_list]
  • 一文读懂 HTTPS:证书体系与加密流程
  • Percona pt-archiver 出现长事务
  • GISBox实操指南:如何将IFC文件高效转换为3DTiles格式‌‌
  • 【MAC电脑系统变量管理】
  • 基于Zig语言,opencv相关的c++程序静态交叉编译
  • 微服务-springcloud-springboot-Skywalking详解(下载安装)
  • 设置后轻松将 iPhone 转移到 iPhone
  • 基于SpringBoot+Uniapp的健身饮食小程序(协同过滤算法、地图组件)
  • Socket编程入门:从IP到端口全解析
  • C语言(长期更新)第5讲:数组练习(三)
  • Apache 消息队列分布式架构与原理
  • 开发避坑短篇(5):vue el-date-picker 设置默认开始结束时间
  • LLM层归一化:γβ与均值方差的协同奥秘