实用指南:【设计模式】适配器模式 在java中的应用

news/2025/9/26 13:49:50/文章来源:https://www.cnblogs.com/tlnshuju/p/19111046

实用指南:【设计模式】适配器模式 在java中的应用

2025-09-25 13:45  tlnshuju  阅读(0)  评论(0)    收藏  举报

文章目录

      • 适配器模式简介
        • 为什么需要适配器模式?
        • 类比
      • 适配器模式的结构与角色
        • 目标接口(Target)
        • 需要适配的类(Adaptee)
        • 适配器(Adapter)
        • 结构图示意
      • 适配器模式的实现方式
        • 类适配器实现(基于继承)
        • 对象适配器实现(基于组合)
      • 适配器模式的实际应用场景
        • 集成第三方库
        • 数据库驱动兼容
        • 旧系统迁移/升级
        • 前端开发中的兼容处理
        • JDK 中的应用
      • 适配器模式的优缺点分析
        • 优点
        • 缺点

适配器模式简介

适配器模式(Adapter Pattern),又称为包装器模式,是一种结构型设计模式。它的核心作用是**“将一个接口转换成客户希望的另一个接口”**,使原本因接口不兼容而无法工作的类可以协同工作。

为什么需要适配器模式?

在实际开发中,我们经常会遇到这样的问题:
我们手头有一个类A(比如老版本的接口),而现在需要用它来适配到一个新接口B(比如新系统的标准)。直接修改A的代码可能不现实(比如A是第三方库),这时候就可以用适配器模式来“桥接”它们。

类比

假设你买了一台美国进口的笔记本电脑,它的电源插头是美标的两扁头,而中国大陆的插座是国标的三孔插座。
你不能直接把美标插头插进国标插座,这时就需要一个插头转换器
插头转换器的作用就是:一边兼容美标插头,一边兼容国标插座,让两个本来“不兼容”的东西可以协同工作。

适配器模式的结构与角色

适配器模式的结构其实很简单,主要包括以下几个角色:

目标接口(Target)

这是客户端期待的接口,也就是系统希望使用的标准接口。
举例:你家里的国标插座就是目标接口。

package com.example.adapter;
public interface Target {
void request();
}

需要适配的类(Adaptee)

这个类是已经存在的,接口不兼容但功能可用。
举例:美标插头的设备就是 Adaptee。

package com.example.adapter;
public class Adaptee
{
public void specificRequest() {
System.out.println("Adaptee: 处理特殊请求");
}
}

适配器(Adapter)

适配器是连接目标接口和需要适配的类的“桥梁”。
它实现了目标接口,并在内部持有 Adaptee 的引用,通过转换让二者协同工作。
举例:插头转换器就是 Adapter。

package com.example.adapter;
// 对象适配器实现方式
public class Adapter
implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
// 在这里做转换,让 Adaptee 能被 Target 使用
adaptee.specificRequest();
}
}

结构图示意
+-----------+         +------------+         +-----------+        +-----------+
|  Client   |  --->   |  Target    |    | Adaptee   |
+-----------+         +------------+         +-----------+        +-----------+
  • Client 通过 Target 接口调用 Adapter
  • Adapter 内部调用 Adaptee 的方法,实现接口转换

小结:
适配器模式的核心结构就是:目标接口(Target)+ 需要适配的类(Adaptee)+ 适配器(Adapter)
适配器实现了目标接口,并通过组合或继承的方式调用 Adaptee 的功能,实现接口的兼容。

适配器模式的实现方式

在 Java 中,适配器模式有两种常见实现方式:类适配器对象适配器
这两种方式本质上都是让“不兼容”的类能用统一的接口,但实现细节略有不同。


类适配器实现(基于继承)

类适配器通过继承需要适配的类(Adaptee),并实现目标接口(Target)。
由于 Java 只支持单继承,所以类适配器模式有一定局限性。

结构示意:

package com.example.adapter;
// 目标接口
public interface Target {
void request();
}
// 需要适配的类
public class Adaptee
{
public void specificRequest() {
System.out.println("Adaptee: 处理特殊请求");
}
}
// 类适配器
public class ClassAdapter
extends Adaptee implements Target {
@Override
public void request() {
// 直接调用父类方法
specificRequest();
}
}

使用示例:

package com.example.adapter;
public class AdapterDemo
{
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
// 输出:Adaptee: 处理特殊请求
}
}

特点:

  • 适配器通过继承 Adaptee 实现接口转换。
  • 只能适配一个类(受限于 Java 的单继承)。

对象适配器实现(基于组合)

对象适配器通过组合的方式,在适配器内部持有 Adaptee 的实例,并实现目标接口(Target)。

结构示意:

package com.example.adapter;
// 目标接口
public interface Target {
void request();
}
// 需要适配的类
public class Adaptee
{
public void specificRequest() {
System.out.println("Adaptee: 处理特殊请求");
}
}
// 对象适配器
public class ObjectAdapter
implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}

使用示例:

package com.example.adapter;
public class AdapterDemo
{
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
// 输出:Adaptee: 处理特殊请求
}
}

特点:

  • 适配器通过组合 Adaptee 实例实现接口转换。
  • 可以适配多个类(更灵活,推荐使用)。

小结:

  • 类适配器:继承 Adaptee,适用于单继承场景,结构简单但灵活性较低。
  • 对象适配器:组合 Adaptee,更常用,灵活性高,推荐实际开发中优先选择。

适配器模式的实际应用场景

适配器模式在实际开发中非常常见,尤其是在系统集成、旧接口兼容、新旧系统迁移等场景。下面用具体例子和类比,帮助你理解适配器模式的实际应用。


集成第三方库

场景说明:
假设你在项目中需要用到一个第三方的日志库(如 Log4j),但你的系统统一使用了自定义的 Logger 接口。如果直接改动系统代码成本太高,可以为第三方库写一个适配器,让它实现你的 Logger 接口。

代码示例:

package com.example.adapter;
// 系统要求的日志接口
public interface Logger {
void log(String message);
}
// 第三方日志库
import org.apache.log4j.Logger as Log4jLogger;
public class Log4jAdapter
implements Logger {
private Log4jLogger log4jLogger;
public Log4jAdapter(Log4jLogger log4jLogger) {
this.log4jLogger = log4jLogger;
}
@Override
public void log(String message) {
log4jLogger.info(message);
// 转换到第三方库的方法
}
}

数据库驱动兼容

场景说明:
假如你的系统原本用的是 MySQL 数据库,后来需要支持 PostgreSQL,但你的 DAO 层接口是统一的。可以写一个适配器,把 PostgreSQL 的驱动方法适配成你的 DAO 接口。


旧系统迁移/升级

场景说明:
公司老系统的接口和新系统不兼容,但又不能一下子全部重写。可以用适配器模式,将新系统的接口适配到老系统的实现,让二者能共同运行。


前端开发中的兼容处理

场景说明:
比如你用 Vue3 编写新组件,但项目里还有很多 Vue2 的代码,可以通过适配器模式包装 Vue2 组件,让它们可以在 Vue3 环境下运行。


JDK 中的应用

场景说明:
Java 标准库里也大量使用适配器模式。例如 java.io.InputStreamReader 适配了 InputStreamReader,让字节流可以作为字符流处理。

源码片段:

// InputStreamReader.java
public class InputStreamReader
extends Reader {
private final InputStream in;
public int read(char[] cbuf, int offset, int length) throws IOException {
// 实现将字节流转换为字符流
}
}

适配器模式的优缺点分析

优点

提高代码复用性
可以复用已有的功能类(Adaptee),不需要修改原有代码,只需通过适配器进行接口转换。

增强系统灵活性和扩展性
适配器模式让系统能够兼容更多的第三方类或旧系统,便于后期扩展和集成。

解耦系统各模块
客户端只依赖目标接口(Target),不关心具体实现细节,有利于降低模块间耦合度。

满足“开放-封闭原则”
通过新增适配器类来适配不同接口,无需修改原有代码,符合 OCP 原则。


缺点

增加系统复杂度
引入适配器后,系统类的数量增加,结构变得更加复杂,理解和维护成本提升。

适配器编写成本
每当有新的 Adaptee 需要适配时,都要编写新的适配器类,增加开发工作量。

可能影响性能
适配器模式通常会增加一次方法调用(间接层),在高性能要求场景下可能略有影响。

只能适配“接口”不兼容,不能解决“业务”不兼容
适配器只能转换接口,无法解决业务逻辑上的差异,如果 Adaptee 的业务与 Target 差异过大,适配器模式就不适用了。

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

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

相关文章

日记4

今天接着学Java,直接从类和对象入手。理解类是模板,对象是实例,像设计图纸和盖好的房子。试着写简单类定义对象,一开始老把属性和方法弄混,改了几次代码,终于成功创建对象并调用方法,感觉对面向对象的思路更清晰…

P2042 [NOI2005] 维护数列 题解

QwQP2042 [NOI2005] 维护数列 题解 平衡树 因为操作里面有翻转,严格强于文艺平衡树,所以考虑平衡树维护数列。直接暴力插入即可 分裂出删除的子段,然后合并其两端的平衡树 分裂出修改的子段,然后打推平的懒标记, …

达梦数据库查询字段类型为Date 修改为DateTime

SELECT ALTER TABLE || OWNER || . || TABLE_NAME || MODIFY || COLUMN_NAME || DATETIME; AS alter_sql FROM ALL_TAB_COLUMNS WHERE DATA_TYPE = DATE and OWNER=PS_EXAMPLEDBUSER order by COLUMN_NAME asc

详细介绍:PyTorch 神经网络工具箱

详细介绍:PyTorch 神经网络工具箱pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&…

C++ new 操作符在操作系统层执行了什么操作?

C++ new 操作符在操作系统层执行了什么操作?在C++中,new操作符的执行涉及操作系统层面的内存分配和对象构造过程,具体可分为以下几个关键步骤: 1. 调用内存分配函数(operator new) new操作符首先通过operator ne…

[ABC422F-G] 题解

QwQ[ABC422F-G] 题解 F - Eat and Ride 考虑 DP,DP 状态要么压和要么压长度,如果压和就很直接,但是显然复杂度会爆炸,如果压长度的话,可以发现每到一个新点都要算:这条路径中在它后面的点的个数乘上它的点权,所…

天津模板建站代理wordpress增加赞赏

代码参考:《重学Java设计模式小傅哥》 目录1、静态类使用2、懒汉模式(线程不安全)3、懒汉模式(线程安全)4、饿汉模式(线程安全)5、使用类的内部类(线程安全)6、双重锁检验…

最新获取网站访客qq接口推客平台有哪些

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 媒体邀约的好处主要体现在提高品牌知名度、扩大受众群体以及与媒体建立良好的合作关系。 媒体邀约是一种有效的公关策略,通过吸引媒体关注来促进信息的传播。它可以帮助组织…

山东省住房和城乡建设部网站首页四川润邦建设工程设计有限公司网站

大家好,我是阿赵。   这篇文章我想写了很久,是关于Unity项目使用AssetBundle加载资源时的内存管理的。这篇文章不会分享代码,只是分享思路,思路不一定正确,欢迎讨论。   对于Unity引擎的资源内存管理,我…

公司网站模板源代码常州微网站建设文档

如果有客户端1、客户端2等N个客户端争抢一个 Zookeeper 分布式锁。大致如下: 1: 大家都是上来直接创建一个锁节点下的一个接一个的临时有序节点 2: 如果自己不是第一个节点,就对自己上一个节点加监听器 3: 只要上一…

c# Listdynamic 按字段排序

public static List<dynamic> OrderByKey (this IList<dynamic> list, string propertyName, bool isDescending = false){var propertyInfo = list[0].GetType().GetProperty(propertyName);if (isDescen…

你看到的和你想要的

你看到的和你想要的 漫思

建设一个货代网站想要多少钱做谷歌网站使用什么统计代码

官方文档&#xff1a;入门指南 | Selenium Selenium是一个用于Web应用测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。 所以使用这个前端测试话工具&#xff0c;可以自动化做很多事情&#xff0c;比如自动化抓取网页内容&#xff0c;俗称网…

大兴网站定制开发房地产招新人的坑

依赖倒转原则 在大话设计模式这本书中&#xff0c;作者通过电话修电脑这个例子引入了面向对象设计的基本原则之一&#xff1a;依赖倒转原则。 概念 依赖倒转原则是面向对象设计的基本原则之一&#xff0c;它用于减少类之间的耦合&#xff0c;提高系统的灵活性和可维护性。在…

东莞网站制作电话糗事百科 wordpress

文章目录1. 题目2. 解题1. 题目 给定一个字符串 s&#xff0c;将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回符合要求的最少分割次数。 示例: 输入: "aab" 输出: 1 解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文…

济南网站建设公司 推荐行知科技自己做网站用什么app

前言 本文主要介绍Redis的三种持久化方式、AOF持久化策略等 什么是持久化 持久化是指将数据在内存中的状态保存到非易失性介质&#xff08;如硬盘、固态硬盘等&#xff09;上的过程。在计算机中&#xff0c;内存中的数据属于易失性数据&#xff0c;一旦断电或重启系统&#…

别再靠 “关设备” 减碳!EMS 的 “预测性控能”,让企业满产也能达标双碳

在 “双碳” 目标推进的当下,减碳已成为企业发展的必答题。然而,不少企业仍陷入 “减碳就减产” 的困境 —— 为了降低碳排放,不得不采取关停生产线、限制设备运行时长等简单粗暴的方式,结果导致订单交付延迟、产能…

双活、异地多活架构怎么设计才不翻车? - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

阿里云客服界面

阿里云客服界面 漫思