适配器模式通过轻量转换层使新系统调用旧逻辑而不修改老代码:目标接口定义标准契约,被适配者提供原始能力,适配器组合其实例并处理参数、返回值及异常的三层不匹配,支持可观察、可切换与平滑演进。

适配器模式不是用来“改接口”,而是让新系统能自然调用旧逻辑——不碰老代码,不破坏现有流程,只加一层轻量转换。
明确谁是目标、谁是被适配者
先理清三类角色,避免一上来就写类:
-
目标接口(Target):你当前业务系统正在使用的标准接口,比如
UserService.queryUser(QueryRequest),所有新模块都按这个契约调用 -
被适配者(Adaptee):第三方库或遗留模块提供的原始能力,比如
LegacyUserApi.findUserById(String id),参数类型、返回结构、异常处理都不同 - 适配器(Adapter):一个普通类,实现目标接口,内部持有被适配者实例,把入参转成它能懂的格式,再把它的返回值包装成目标接口要求的结构
用对象组合,别用继承
Python 和 Java 都推荐对象适配器(组合),因为耦合低、易测试、可替换:
- 适配器类里声明一个私有字段,类型是被适配者的具体类(如
self.legacy_api = LegacyUserApi()) - 构造时注入实例,方便单元测试中用 mock 替换
- 避免继承被适配者类——它可能有副作用、状态依赖,还可能封死扩展路径
- 如果被适配者本身是接口(如
OldUserService),适配器只需持有一个该接口的引用,进一步解耦
重点处理三类不匹配
实际接入时,多数问题集中在以下三个层面,适配器要逐层转化:
-
参数不匹配:目标接口传的是
QueryRequest对象,老接口只收String userId→ 适配器从中提取字段,做非空校验和格式转换 -
返回值不匹配:老接口返回
Map<String, Object>,目标接口要返回UserVo→ 适配器负责字段映射、空值处理、类型转换(如时间戳转 LocalDateTime) -
异常语义不一致:老接口抛
RemoteException,而业务层统一捕获BizException→ 适配器在try-catch中做异常翻译,不向上暴露底层细节
让适配行为可观察、可切换
上线后不能变成黑盒,尤其涉及关键路径的老接口:
- 在适配器关键路径加日志,标记“via LegacyUserAdapter”,便于链路追踪
- 用配置开关控制是否启用适配器(如
feature.legacy-user.enabled=true),灰度期间可快速回退 - 对外暴露简单健康检查方法(如
isLegacyBackendHealthy()),供监控系统采集 - 后续若老服务下线,只需替换适配器实现,或直接删掉该适配器,业务代码零修改

















