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

设计模式实战篇(七):适配器模式 —— 让“不兼容的接口”优雅合作的万能转换器

在真实工程里,适配器几乎无处不在:框架升级、第三方 SDK 接入、系统重构、旧系统兼容、新旧协议过渡……
适配器模式就像“接口世界的翻译官”,让原本不兼容的对象继续合作而无需修改源代码。


🔌 一、为什么需要适配器?(从真实工程痛点开始)

在软件工程中,你一定遇到过这些情况:

场景 1:旧系统接口无法直接迁移到新系统

旧方法签名为:

User getUser(String userId);

但新系统要求:

UserVo queryUser(QueryRequest request);

你不能改旧代码,却要兼容新接口。

场景 2:接入第三方 SDK,但对方接口与你系统完全不同

例如你的日志系统使用:

log.info(String message)

而新引入的云监控需要:

send(LogData data)

场景 3:API 协议升级后,不想引发全系统改动

例如多个模块还在调用旧方法,而你希望:

  • 不修改老代码
  • 新功能走新接口
  • 二者共存

🔥 这些问题的共同点是:
❌ 必须兼容旧结构,但不能修改旧代码
❌ 两个接口不一样,却必须能一起工作

这就是适配器模式的用武之地。


🧭 二、适配器模式核心

适配器 ≈ 转换插头
让使用者不用关心“电压是否一致”,你只提供一个 能把 A 变成 B 的中间层

简单来说:
调用旧接口的代码不变 → 适配器负责把调用转换成新接口格式。


🧱 三、适配器的三种形态

适配器模式有 3 种常见用法:

1)类适配器(继承实现)

通过 extends

LegacyServiceAdapterNewService

适合:必须复用父类逻辑、单继承足够时
缺点:受限于继承

2)对象适配器(组合方式,最常用)

结构:

Adapter 里面持有 NewService

优点:

  • 灵活
  • 不受继承限制
  • 可以适配多个不同的实现
    这是实际项目最常见的方式。

3) 接口适配器(抽象类 + 空实现)

用于需要实现多个方法,但你只关心部分方法的场景,例如:

  • MouseListener
  • KeyListener
    避免实现一堆你不需要的方法。

🔧 四、业务案例:支付系统迁移

假设老系统支付接口是:

public interface OldPayService {boolean pay(String uid, double amount);
}

而新架构统一支付中心的接口是:

public interface NewPayGateway {PayResult process(PayRequest request);
}

两者格式完全不同,但你现在:

  • 不能改老代码
  • 不能让 N 个业务线全部重写逻辑
  • 只能通过适配器融合它们

🎛️ 五、实现演进:从问题到最终解法

初版:业务线硬编码转换

newPayGateway.process(new PayRequest(uid, money));

问题:

  • 所有业务线都要改代码
  • 耦合严重
  • 出错概率极高
    🚫 不符合开闭原则

第二版:写一个工具类

PayResult pay(String uid, double amount) {return newPayGateway.process(new PayRequest(uid, amount))
}

问题:

  • 老接口 OldPayService 丢失
  • 多模块接入仍要改

第三版:对象适配器

让适配器实现老接口,内部调用新接口:

public class PayAdapter implements OldPayService {private final NewPayGateway gateway;public PayAdapter(NewPayGateway gateway) {this.gateway = gateway;}@Overridepublic boolean pay(String uid, double amount) {PayRequest req = new PayRequest(uid, amount);PayResult res = gateway.process(req);return res.getCode() == 200;}
}

🔥 外部业务不需要改任何代码!


🧱 六、适配器的结构拆解.

调用方(旧逻辑)│▼OldPayService   ←(保持不变)│▼
【适配器:PayAdapter】│   把旧方法转成新格式▼NewPayGateway

核心过程:

  1. 旧接口 → 调用适配器
  2. 适配器 → 把参数包装成新格式
  3. 新系统处理
  4. 适配器再次转换 → 旧系统可理解的结果

❌ 七、常见误区

误区 1:适配器用多了会变成“复杂度黑洞”

过度适配=系统过多“翻译层”:

AAdapter1Adapter2Adapter3B

💡 建议:

  • 每条路径最多 1 个适配器
  • 对老接口做“最终适配”,而不是层层递归

误区 2:适配器 ≠ 工厂模式

区别适配器工厂
目的让两个不兼容的接口合作负责创建对象
本质转换器构建器
作用时间运行时创建时

很多面试题故意混淆这一点。

误区 3:适配器不是为了“性能”,而是为了“兼容”

适配器本身会带来额外开销,例如对象转换,这很正常。
它的价值是 解耦 + 兼容,不是加速。


🧩 八、代码示例

1. 老接口

public interface OldPayService {boolean pay(String uid, double amount);
}

2. 新接口

public interface NewPayGateway {PayResult process(PayRequest request);
}

3. 适配器

public class PayAdapter implements OldPayService {private final NewPayGateway gateway;public PayAdapter(NewPayGateway gateway) {this.gateway = gateway;}@Overridepublic boolean pay(String uid, double amount) {PayRequest req = new PayRequest(uid, amount);PayResult res = gateway.process(req);return res.getCode() == 200;}
}

4. 使用方式

OldPayService payService =new PayAdapter(new NewPayGatewayImpl());payService.pay("U1001", 99.0);

业务方无感知:✔


🛰️ 九、适配器的案例

1)协议适配(Protocol Adapter)

例如你的网关接受:

  • HTTP/JSON
  • gRPC
  • MQ
  • WebSocket
  • Protobuf
  • 内网自定义二进制协议

但你的业务服务只认:

统一内部协议 InternalDTO

此时网关需要多个适配器:

JsonAdapter → InternalDTO  
GrpcAdapter → InternalDTO  
MqAdapter → InternalDTO  
ProtoAdapter → InternalDTO

🌉 十、跨语言适配(Java ⇆ Python ⇆ Go)

现代企业经常有多语言服务,例如:

  • Java(主线)
  • Python(AI 服务)
  • Go(高性能网关)
    这些服务的 DTO、字段、结构往往不同。

适配器可用于:

  • 字段映射
  • 类型转换
  • 语言间协议编码、解码
  • 图像/embedding 数据统一格式化
  • RPC 桥接

示例(Java 端 Adapter 适配 Python 返回的 Map):

public class PythonUserAdapter implements UserDomainObject {private final Map<String, Object> pythonMap;public PythonUserAdapter(Map<String, Object> pythonMap) {this.pythonMap = pythonMap;}@Overridepublic String getName() {return (String) pythonMap.get("username");}@Overridepublic int getAge() {return ((Number) pythonMap.get("age")).intValue();}
}

🧬 十一、架构演进中的适配器

当系统重构时:

  • DTO 变了 → 写适配器
  • 服务名变了 → 写适配器
  • 方法签名变了 → 写适配器
  • 接口调用方过多无法改 → 写适配器

适配器承担 兼容老代码 的任务,让重构:

  • 不影响运行
  • 可平滑迁移
  • 可灰度发布
  • 可随时回滚旧版本

🔭 十二、适配器与相关模式对照

模式容易混淆原因本质区别
适配器两边接口不同使“不兼容接口”合作
外观(Facade)都是“包装”外观是“统一多接口”,不是转换接口
代理(Proxy)都有“中间层”代理用于控制访问(缓存、权限)
装饰器(Decorator)都是“包装”装饰是增强功能,不修改接口本身
桥接(Bridge)都是“结构型模式”桥接是抽象与实现分离,不做接口兼容

🧠 十三、进一步的工程技巧:适配器注册中心

在协议多样的大型系统中,仅仅创建适配器不够,需要:

  • 可动态加载
  • 可根据协议自动选择适配器
  • 可对同一协议多版本适配
  • 可扩展

示例:

public class AdapterRegistry {private static final Map<String, Adapter> ADAPTERS = new HashMap<>();public static void register(String key, Adapter adapter) {ADAPTERS.put(key, adapter);}public static Adapter get(String key) {return ADAPTERS.get(key);}
}

注册适配器:

AdapterRegistry.register("json", new JsonAdapter());
AdapterRegistry.register("grpc", new GrpcAdapter());
AdapterRegistry.register("mq", new MqAdapter());

调用:

Adapter adapter = AdapterRegistry.get(protocolType);
adapter.convert(request);

🔥 优点:

  • 插拔式适配
  • 可配置化(适合 Spring 配置)
  • 扩展性极强
  • 非常适合网关/中台

🎯 总结

适配器模式解决了软件工程中最痛苦的问题之一:

“接口已经不兼容了,但我们还不能重构老代码。”

它既是过渡方案,也是企业级架构的稳定器。

http://www.dtcms.com/a/618975.html

相关文章:

  • 【Java 基础】5 面向对象 - 实体类
  • 波哥昆明网站建设平面设计的素材网站
  • 外贸网站推广收费自己做个网站好还是做别人会员好
  • MySQL---C/C++链接
  • 怎么进入微信官方网站汉字logo标志设计
  • 深入理解 Java Stream 流:函数式编程的优雅实践(全面进阶版)
  • 高端网站制作报价网站怎么做搜索
  • CSS Fonts(字体)
  • 莱芜手机网站设计公司网站上传到空间
  • skywalking整合logback.xml日志,日志文件出现乱码问题解决
  • 网站建设栏目添加收费电影网站怎么做
  • 【LwIP源码学习8】netbuf源码分析
  • 蓝牙EIR数据
  • 外企网站建设中国庆阳网
  • nfs共享服务
  • vue2[webpack]中接入vue3[vite]的qiankun微前端服务
  • Apache Hadoop-学习笔记1
  • 网站年龄和域名年龄贸易公司怎么做网站比较好
  • 如何拥有一个自己的网站网站安全管理制度建设下载
  • 有做阿里网站的吗网站开发后未付维护费
  • 百度推广必须做手机网站吗网页游戏网站mhn
  • 2018做网站的视频个人直播平台搭建
  • OpenAI 最新研究进展:定义和评估大语言模型中的政治偏见:OpenAI的透明度承诺
  • Streamlit 莫斯电码转换器学习笔记
  • 告别传统PPT!用reveal.js在文汇百川webOS上打造酷炫动态演示
  • 什么是行业网站?揭阳企业建站系统
  • 如何让新网站18.ppt网站是谁做的
  • 第四十三篇:MySQL事务:ACID特性、隔离级别与幻读、脏读详解
  • 网页设计个人网站设计wordpress 头部菜单
  • wordpress网站怎么加小游戏江门市住房和城乡建设局门户网站