← 返回题目列表

适配器模式如何用于老接口兼容和系统迁移?

高频 中等 第 9 / 25 题 更新于 2026/07/28
适配器模式老系统改造接口兼容系统迁移设计模式

简化版

老接口兼容中,适配器可以把旧接口包装成新接口,或者把新实现包装成旧接口,让调用方在迁移过程中不用一次性全部修改。它常用于渐进式重构、第三方替换、接口升级和新旧系统并行。

详细版

系统迁移最怕“一刀切”。如果新接口上线后要求所有调用方同时改造,风险很高。适配器模式可以在新旧接口之间加一层转换:

  1. 旧系统能力还在,新增适配器实现新接口;
  2. 新系统已经完成,但老调用方仍调用旧接口,新增反向适配器兼容旧接口;
  3. 多个历史版本接口并存,通过适配层统一到内部标准模型;
  4. 第三方供应商切换时,业务层继续依赖统一接口。

适配器的关键是隔离变化。调用方看到的是稳定接口,迁移差异集中在适配层。这样可以按业务线、流量比例、版本逐步迁移。

但要注意:适配器只能解决接口形态差异,不能掩盖业务语义差异。如果新旧接口语义不一致,需要在迁移设计中明确兼容规则。

完整版教学

一、老接口迁移为什么容易出问题

老系统通常有很多调用方:

订单系统 -> 老库存接口
促销系统 -> 老库存接口
客服系统 -> 老库存接口
报表系统 -> 老库存接口

如果新库存接口上线后,要求所有系统立刻改调用方式,风险很大:

  • 调用方太多;
  • 改造周期不同;
  • 测试范围扩大;
  • 回滚困难;
  • 新旧数据语义可能不同。

适配器模式适合用来降低这种迁移风险。

二、旧能力适配成新接口

假设新接口是:

interface StockService {
    boolean lockStock(String skuId, int count);
}

但旧系统只有:

class OldStockClient {
    String freeze(String itemCode, String num) {
        return "SUCCESS";
    }
}

可以写适配器:

class OldStockAdapter implements StockService {
    private final OldStockClient oldClient;

    public boolean lockStock(String skuId, int count) {
        String result = oldClient.freeze(skuId, String.valueOf(count));
        return "SUCCESS".equals(result);
    }
}

这样新业务先面向 StockService,底层暂时仍然调用旧系统。

三、新实现兼容旧接口

有时情况相反:新系统已经上线,但还有老调用方只认识旧接口。

这时可以写反向适配器,让老调用方暂时不改代码:

老调用方 -> 旧接口适配器 -> 新库存服务

这种方式给调用方争取迁移时间,避免所有系统同一天切换。

四、适配层适合做版本隔离

接口升级时经常出现多个版本:

V1 请求模型
V2 请求模型
V3 请求模型

内部系统最好不要到处处理这些版本差异。可以在入口适配层把不同版本转换成内部统一模型:

V1Adapter -> InternalCommand
V2Adapter -> InternalCommand
V3Adapter -> InternalCommand

业务核心只处理 InternalCommand,版本差异留在边界层。

五、适配器帮助渐进式重构

渐进式重构常见做法是:

  1. 定义新的目标接口;
  2. 让旧实现通过适配器实现目标接口;
  3. 新代码只依赖目标接口;
  4. 逐步替换底层旧实现;
  5. 调用方迁移完成后删除旧适配器。

这种路线比一次性大改安全得多。

六、适配器不能掩盖语义差异

如果旧接口的 freeze 是“冻结库存”,新接口的 lockStock 是“锁定并扣减库存”,两者语义并不等价。

这种情况下,适配器里强行转换会埋雷。正确做法是明确语义差异:

  • 是否需要补充调用;
  • 是否只能兼容部分场景;
  • 是否需要降级处理;
  • 是否需要新字段;
  • 是否需要数据校验。

接口形态能适配,业务语义不能随便糊。

七、双写迁移与可撤销切换

迁移 100 个调用点时先让 Adapter 保持旧接口,按 10%→50%→100% 流量切新实现;每阶段比较成功率和结果差异。

old callers -> compatibility adapter -> old/new implementation via flag

适配器的验收标准不是“调用成功”,而是 Target 的业务语义在转换前后保持成立。参数、单位、时区、精度、空值、错误码和资源所有权都应逐项形成契约样例,否则最危险的错误会以“成功响应”的形式潜伏。

八、语义边界与契约样例验证

检查维度应确认的内容
机制正确性适配器支持渐进迁移的价值,在于把调用方改造和实现切换拆成可回滚步骤。
适用边界适配层应有下线计划和监控,不能无限叠加 v1→v2→v3 多层转换,最终没人理解真实语义。
测试证据注入 Adaptee 测试替身,断言外部请求、返回映射、异常转换和调用次数
工程代价重点统计字段映射与对象分配成本、外部模型变更影响面,以及多层版本适配造成的认知债务

易错点:适配器支持渐进迁移的价值,在于把调用方改造和实现切换拆成可回滚步骤。

九、常见误区与追问

  • 误区:加了适配器后旧接口可以永久不治理。 长期兼容会积累模型和语义债务,应统计调用量并设置弃用与删除节点。
  • 误区:适配器只需要让方法签名能够编译。 真正的适配还包括单位、时区、错误码、空值、资源释放和幂等语义;签名一致不代表行为兼容。
  • 追问:新旧结果不一致怎么灰度? 影子调用或双读比较但只采信一个结果,记录差异,确认副作用接口不能盲目双写。
  • 追问:适配器应该放在哪一层? 通常放在系统边界或防腐层,让业务层只依赖 Target,避免第三方模型和异常向内扩散。
  • 追问:适配器测试为什么需要契约样例? 因为类型相同仍可能单位、精度或错误语义不同;契约样例能证明转换后的行为而不只是编译通过。

十、加强记忆

适配器用于老接口兼容时,可以记成“新旧系统中间搭桥”。旧能力可以适配成新接口,新实现也可以反向兼容旧接口,适合渐进式迁移和版本隔离。关键是把差异关在适配层,同时警惕新旧接口业务语义不一致。