当前位置: 首页 > 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.dtcms.com/a/295582.html

相关文章:

  • vue 中什么场景使用 export default 和setup()
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现卫星图像识别(C#代码,UI界面版)
  • [数据结构]#6 树
  • Apache Commons:Java开发者的瑞士军刀
  • 【C++】使用箱线图算法剔除数据样本中的异常值
  • n8n AI资讯聚合与分发自动化教程:从数据获取到微信与Notion集成
  • 环特生物荣获“广西科学技术进步二等奖”
  • C++ 协程
  • 移动端自动化Appium框架
  • Linux服务器安全自动化审计实战:一键扫描账户/网络/进程/计划任务风险(附开源脚本)
  • rna_seq_pipeline.py-python002
  • 同步时钟系统提升仓库自动化水平
  • 服务器启动日志等级
  • 锁定锁存器 | 原理 / 应用 / 时序
  • 无广告终端安全产品推荐:打造纯净办公环境的安全之选
  • 【Spring Cloud Gateway 实战系列】终极篇:演进方向与未来架构
  • Gitea——私有git服务器搭建教程
  • AWS云S3+Glue+EMRonEC2+ReadShift
  • RK3568笔记九十一:QT环境搭建
  • 2025创新杯(钉钉杯)数学建模 AB赛题已出
  • ESP32S3 Ubuntu vscode如何使用USB-JTAG调试
  • VR全景制作的流程?VR全景制作可以用在哪些领域?
  • 【算法】分治
  • Ubuntu 20.04 上安装 SPDK
  • RP2040关键汇编函数解释
  • 旧物回收小程序系统开发——开启绿色生活新篇章
  • 基于区块链的商品销售系统(fiscobcos)
  • 本地部署dify1.7.0流程-windows docker
  • [AI 生成] Flink 面试题
  • 企业ERP系统全模块深度解析:从基础管理到智能运营