java适配器模式通过“翻译层”兼容老旧系统:目标接口(target)是新契约,被适配者(adaptee)是不可修改的旧逻辑,适配器(adapter)组合adaptee并做纯转义;推荐对象适配器,用构造注入、字段映射、异常翻译等实现参数、返回值、异常三类不匹配的精准对齐;多旧源时引入工厂解耦;适配器须职责单一,只转义不掺业务逻辑。

Java 中接口结合适配器模式兼容老旧系统,关键不是改老代码,而是加一层“翻译层”——让新系统按标准接口调用,底层稳稳跑着旧逻辑。
明确三个角色,从契约出发
别一上来就写类,先理清谁是“甲方”,谁是“乙方”:
-
目标接口(Target):新系统正在依赖的标准契约,比如
UserQueryService.queryById(String id)或PaymentService.pay(Order order); -
被适配者(Adaptee):你不能动的老旧类或接口,例如
LegacyUserApi.findUser(long userId)或OldPayment.doPay(String orderId, double amountYuan); - 适配器(Adapter):一个普通 Java 类,实现 Target 接口,内部持有 Adaptee 实例,只做字段映射、单位换算、结构拆分等纯转义操作。
用对象适配器,组合优于继承
Java 不支持多继承,类适配器(继承 Adaptee + 实现 Target)易受限制,且耦合高、难测试。推荐对象适配器:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 适配器类声明私有字段:
private final LegacyUserApi legacyApi; - 构造器注入实例,便于单元测试中 mock 替换;
- 所有方法都基于该字段委托调用,并完成必要转换,例如:
public UserVo queryById(String id) { return convert(legacyApi.findUser(Long.parseLong(id))); }
重点处理三类不匹配
实际卡点往往在变量层面,适配器要精准对齐:
-
参数不一致:目标传
QueryRequest对象,老接口只收String userId→ 适配器提取字段、校验非空、格式转换; -
返回值不一致:老接口返回
Map<string object></string>或 JSON 字符串,新接口要UserVo→ 适配器做字段映射、空值兜底、时间戳转LocalDateTime; -
异常语义不一致:老接口抛
IOException或自定义LegacyException,业务层统一捕获BizException→ 适配器用 try-catch 完成异常翻译,不暴露底层细节。
多旧源接入时,加个简单工厂
当不止一个老旧系统要对接(如 LegacySystemA、LegacySystemB),避免硬编码多个适配器:
- 定义统一适配器接口,如
UserAdapter; - 各具体适配器(
AUserAdapter、BUserAdapter)都实现它; - 工厂类根据来源标识(如
systemType = "A")返回对应实例; - 上层业务只面向
UserAdapter编程,新增旧源只需加类 + 工厂分支,零改动已有逻辑。
守住边界:只转义,不掺活
适配器必须职责单一,否则会变成维护黑洞:
- 不做业务判断(如权限校验、流程分支);
- 不修改老对象状态,只读取并转换;
- 日志、缓存、重试、熔断等能力全部交给上层或中间件;
- 异常尽量透传或标准化包装,不在适配层吞掉原始错误信息。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










