适配器模式核心是“包住旧接口、转清数据异常、控住资源线程”,用对象适配器组合legacybillingservice,实现paymentprocessor,转换参数/异常/返回值,并透传上下文。

直接用适配器模式桥接旧接口和新架构,关键不是“改老代码”,而是“包住它、转清楚、控得住”。核心是让新系统只认目标接口,完全感知不到老逻辑的存在。
明确三类角色,别混淆职责
目标接口(Target)是新系统定义的契约,比如 PaymentProcessor.process(PaymentRequest);适配者(Adaptee)是旧系统提供的类,比如 LegacyBillingService.charge(String orderId, double amount);适配器(Adapter)必须实现 Target,并持有 Adaptee 实例——它不继承老类,也不暴露老方法,只做转换。
优先选对象适配器,避开继承陷阱
类适配器依赖继承,但老服务常是 final 类、无源码或已封装成 jar,根本无法继承。对象适配器用组合更稳妥:
- 适配器构造器中强制校验 Adaptee 是否非 null,避免运行时空指针
- 若老服务有状态(如数据库连接、缓存上下文),适配器应实现 AutoCloseable,并在 close() 中同步释放资源
- Spring 环境下,老服务 Bean 命名建议加 legacy- 前缀(如 @Bean("legacyBillingService")),避免与新 Bean 冲突
转换不止是方法调用,还要处理毛刺细节
真实场景里,不兼容往往藏在数据和异常里:
- 老接口返回 Map
,新契约要 PaymentResult:用静态映射工具类(如 LegacyResponseMapper.toPaymentResult(map)),别手写 get("amount") - 老方法抛 LegacyNetworkException,新协议要求统一返回 Result.failure("timeout"):适配器内必须 catch 并转换,不能让异常穿透出去
- 老参数是 String userId,新系统传的是 UUID:转换逻辑封在适配器里,比如 adaptee.charge(userId.toString(), amount)
测试要覆盖“真实毛刺”,不能只测 happy path
单元测试重点不是验证逻辑对不对,而是验证“桥是否稳”:
- 模拟老服务返回 null 或空 map,检查适配器是否抛出明确业务异常,而非 NPE
- 触发老服务超时异常,确认适配器是否正确包装为 Result.timeout()
- 并发调用适配器,验证线程上下文(如用户认证信息、traceId)是否能从新请求透传到老服务
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











