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

代理模式和适配器模式区别

代理模式 vs 适配器模式 完整详解+核心区别

一、先分别吃透两种模式本质

1. 适配器模式(Adapter,结构型)

核心目的:做「转换兼容」
两个已有接口不匹配,通过适配器做一层接口转换,让原本不能协作的两类代码一起工作。

  • 关键词:兼容、翻译、转换、统一接口
  • 角色:
    • 目标接口 Target:我方程序期望调用的统一接口
    • 被适配者 Adaptee:已有旧接口/第三方类,方法名、参数和我方不匹配
    • 适配器 Adapter:包装 Adaptee,实现 Target,内部做参数、方法转发转换
  • 类比:转换插头
    插座是标准Target(国标三脚),国外电器是Adaptee(美标两脚),适配器插头做转换,让电器插上插座。
两种实现
  1. 类适配器:继承被适配类 + 实现目标接口(Java单继承很少用)
  2. 对象适配器:组合持有被适配对象(主流)

2. 代理模式(Proxy,结构型)

核心目的:做「控制增强」
用一个代理类包装原始目标对象,对外暴露完全一模一样的接口,不修改原有接口定义,在方法前后增加额外逻辑(权限、缓存、日志、延时创建、远程调用)。

  • 关键词:控制、增强、拦截、中介、透明访问
  • 角色:
    • 抽象主题 Subject:原始对象与代理共同实现的统一接口
    • 真实对象 RealSubject:业务核心对象
    • 代理 Proxy:实现同一接口,持有真实对象,拦截所有方法
  • 类比:中介/经纪人
    明星(RealSubject)和经纪人(Proxy)对外联系方式完全一致(都能接演出),但经纪人会做前置筛选报价、后置签合同,明星只负责表演。
常见分类
  • 静态代理:手写代理类
  • 动态代理:JDK动态代理、CGLIB(Spring AOP底层就是动态代理)
  • 远程代理、虚拟代理、保护代理、缓存代理

二、最核心本质差异(一句话区分)

  1. 适配器:接口不一样,做转换,解决「不兼容」
    对外提供新接口,抹平新旧/第三方接口差异;使用者看不到原始类接口。
  2. 代理:接口完全一样,做增强,控制访问
    对外和原始对象完全相同接口,使用者无感知,透明调用,只附加额外逻辑。

关键分水岭:接口是否改变

  • 调用方期望的接口 ≠ 原始类接口 → 适配器
  • 调用方期望的接口 = 原始类接口 → 代理

三、分层详细对比

1. 设计目标不同

适配器

打通两套不兼容接口,复用已有第三方/旧代码,不用修改原有代码。
场景:老系统接口、第三方SDK、不同组件整合。

代理

在不改动原对象代码前提下,对原有功能进行拦截、增强、管控
场景:权限校验、日志、缓存、懒加载、远程RPC、事务、限流。

2. 对外暴露接口

适配器

适配器实现全新的目标接口Target,内部调用被适配者Adaptee的异构方法。
外部调用Adapter的是一套新方法名,和Adaptee方法名完全不同。
示例:

  • Target:pay(amount)
  • Adaptee第三方支付:transferMoney(money, channel)
  • Adapter内部:pay()里转换参数调用transferMoney()
代理

代理和真实对象实现同一个接口Subject,方法名、参数、返回值完全一致。
外部调用Proxy的方法,和直接调用RealSubject无任何区别。
示例:

  • 统一接口:queryOrder(Long id)
  • Proxy.queryOrder() 先查缓存,无缓存再调用 RealSubject.queryOrder()

3. 与被包装对象的关系

适配器

被包装的 Adaptee 是外部/老旧异构组件,本来就不适合当前系统调用规范,两者设计初衷无关。
适配器是翻译官

代理

被包装的 RealSubject 是系统核心业务对象,本身完全满足业务功能,只是需要附加控制逻辑。
代理是保镖/中介

4. 是否改变调用行为

适配器

核心逻辑委托给被适配者,适配器只做参数、格式转换,不新增额外横切逻辑。
没有前置校验、缓存、日志这类增强,仅做格式翻译。

代理

核心逻辑依然委托真实对象,但会增加前后附加逻辑
前置:权限校验、参数校验、缓存查询
后置:日志记录、耗时统计、事务提交

5. 代码示例直观区分

示例1:适配器(接口不匹配,转换)
// 目标接口:系统统一支付标准publicinterfacePayment{voidpay(BigDecimalmoney);}// 第三方老支付SDK(接口不兼容)publicclassOldThirdPay{publicvoidtransfer(BigDecimalcash,Integertype){System.out.println("第三方转账:"+cash);}}// 适配器:统一转换成Payment接口publicclassPayAdapterimplementsPayment{privateOldThirdPayadaptee=newOldThirdPay();@Overridepublicvoidpay(BigDecimalmoney){// 转换参数,适配第三方接口adaptee.transfer(money,1);}}// 使用:业务只认Payment,完全不知道OldThirdPay存在Paymentpay=newPayAdapter();pay.pay(newBigDecimal(100));
示例2:代理(接口完全一致,增加缓存增强)
// 统一抽象接口publicinterfaceOrderService{OrdergetOrder(Longid);}// 真实业务类publicclassOrderServiceImplimplementsOrderService{@OverridepublicOrdergetOrder(Longid){// 查询数据库returndb.selectById(id);}}// 缓存代理,接口完全一致publicclassOrderProxyimplementsOrderService{privateOrderServicereal=newOrderServiceImpl();privateMap<Long,Order>cache=newHashMap<>();@OverridepublicOrdergetOrder(Longid){// 前置增强:缓存拦截if(cache.containsKey(id)){returncache.get(id);}Orderorder=real.getOrder(id);// 后置增强:放入缓存cache.put(id,order);returnorder;}}// 使用方式和原对象完全一致,上层无感知OrderServiceservice=newOrderProxy();service.getOrder(1001L);

6. 适用业务场景对比

适配器典型场景
  1. 整合第三方SDK(微信/支付宝老版本接口、OSS存储、第三方短信)
  2. 新旧系统兼容:老数据库DAO、遗留接口适配新业务框架
  3. 统一多类异构工具:多种日志组件、多种文件存储适配统一工具类
  4. 不同协议转换:HTTP接口适配内部RPC调用格式
代理典型场景
  1. 动态代理做AOP:日志、切面、事务、限流、权限校验(Spring核心)
  2. 缓存代理:数据库查询加本地缓存、Redis缓存
  3. 虚拟代理:大图片/大文件延迟加载(用到才创建真实对象)
  4. 保护代理:接口访问权限校验,未登录拦截调用
  5. 远程代理:RPC客户端代理,屏蔽网络通信细节(Dubbo/Feign)
  6. 静态代理:封装工具类增加统一异常处理

7. 优缺点与取舍

适配器优点

快速兼容异构代码,无需修改第三方/遗留类;统一对外调用标准。
缺点:仅做转换,无法统一增加横切增强逻辑。

代理优点

无侵入增强原有业务,上层调用零改动;动态代理可统一批量切面处理。
缺点:只能用于接口匹配的场景,不能解决接口不兼容问题。


四、表格汇总对比

对比维度适配器模式(Adapter)代理模式(Proxy)
核心职责接口转换、兼容异构组件透明拦截、功能增强、访问控制
对外接口提供全新目标接口,与被包装对象接口不同和原始对象完全相同接口,方法签名一致
设计关系解决「接口不匹配」问题不改变接口,附加额外逻辑
类比转换插头、翻译官经纪人、中介、保镖
包装对象第三方/遗留异构类系统原生标准业务对象
附加逻辑仅参数/格式转换,无横切增强缓存、日志、权限、事务、延时加载
上层感知上层只依赖Target,看不到原始类上层完全无感知,像直接调用原对象
典型框架应用SpringMVC HandlerAdapter、集合工具适配Spring AOP动态代理、Dubbo远程代理

五、极易混淆的边界场景区分技巧

场景1:如果我包装后,方法名变了 → 适配器

需要把sendMsg(String phone,String content)改成系统统一sendSms(SmsDTO dto),参数结构重组,一定是适配器。

场景2:包装后方法名、参数完全不变,只是加日志/缓存 → 代理

getUser(Long id)前后加打印耗时、缓存查询,接口一丝不动,一定是代理。

场景3:同时需要转换+增强怎么处理?

分层组合:外层代理做增强,内层适配器做转换
调用链路:Controller → Proxy(日志/权限)→ Adapter(接口转换)→ 第三方SDK

六、一句话记忆口诀

接口不一样,要兼容,用适配器;
接口一模一样,要增强,用代理。

http://www.cnnetsun.cn/news/3252120.html

相关文章:

  • HarmonyOS 小游戏《对战五子棋》开发第23篇 - 保持棋盘正方形
  • 维度建模实战:电商数仓 6 步构建星型模型,产出 10+ 核心事实/维度表
  • 直流有刷电机驱动方案:TC78H651AFNG与PIC18F85J10实战
  • 02-01-确认环境依赖(全平台发布)
  • 延伸音(Tension)应用指南:属七和弦5种常用Tension音搭配与省略五音原则
  • 【Bug已解决】openclaw network timeout / Connection timed out — OpenClaw 网络超时解决方案
  • 你想不想用一套系统方法,把复杂的医学数据变成清晰结论?
  • QT入门篇
  • ADS131M02与PIC24EP512GU814的高精度ADC系统设计
  • 2026大直径紧固件双叠自锁垫圈怎么选型
  • 使用英特尔流式SIMD扩展优化动画模型的 渲染 流水线
  • MAX77654与PIC18LF46K40的嵌入式电源管理方案
  • 有些软件明明就是财务软件,为什么要说是ERP呢?
  • 终极指南:3分钟掌握Boss-Key老板键,一键保护你的数字隐私空间
  • MP2672A双节锂电池充电管理与STM32控制方案
  • 如何用AI快速移除图片和视频背景?BackgroundRemover完整指南
  • 夏天,死磕这 6 个燃脂行为,体脂率下降 5%!
  • Steam挂刀神器:5分钟搭建你的饰品交易监控系统,发现隐藏利润空间!
  • 终极指南:如何彻底解决MHY扫码器直播监视功能崩溃问题 [特殊字符]
  • 有没有覆盖全学段的靠谱论文 AI?整理一份不白花冤枉钱工具榜单
  • Flink 1.18.0 本地模式性能初探:WordCount作业737ms运行时间分析
  • Go入门:代码格式化与gofmt使用指南
  • TRAE:面向 Vue 3 移动端开发的 AI IDE 工作流
  • Kilo Code:面向工程落地的跨端AI编程加速器
  • EB Tresos 26.2.0 配置 TC389 CAN/LIN:从硬件原理图到通信测试的 7 步实战
  • 【Bug已解决】Claude Code MCP server connection timeout — Claude Code MCP 连接超时解决方案
  • Agent 核心原理:把关键能力落到项目里
  • Caspar:基于符号编程的GPU加速非线性优化库
  • 矢量积法与微分变换法:2 种雅可比矩阵求解方案的 MATLAB 实现与对比
  • BQ25887充电管理芯片与MCU在电池平衡系统中的应用