1、接口适配基础:什么是接口适配、适配器模式原理、接口适配的常见场景

各位同学,咱们今天聊聊接口适配。说实话,这玩意儿听起来有点学术,但说白了,就是「让两个不兼容的东西能一起工作」。我做了十几年系统,几乎每个项目都会碰到这类问题。

你想想看,现实世界里,你拿个 Type-C 充电器去给老款 Micro-USB 手机充电,中间缺个转接头,就充不进去。软件系统也一样。两个模块接口对不上,数据就传不过去。这时候,适配器就派上用场了。

1.1 什么是接口适配

接口适配,核心就一句话:在不修改原有代码的前提下,让两个不兼容的接口协同工作。

我记得刚入行那会儿,接手一个遗留系统。老系统输出 XML,新模块只认 JSON。改老系统?风险太大。改新模块?业务逻辑全耦合在里面。最后我加了一层适配器,两边都没动,问题就解决了。

核心原则:

  • 对现有代码零侵入
  • 调用方无需感知底层变化
  • 适配层可独立测试、独立部署

适配的本质,就是做一层「翻译」。把 A 的请求翻译成 B 能理解的格式,再把 B 的响应翻译回 A 能读懂的格式。嗯,就这么简单。

1.2 适配器模式原理

适配器模式是 GoF 23 种设计模式之一。它分两种:类适配器和对象适配器。我个人更常用对象适配器,因为组合优于继承,灵活性更高。

咱们直接看代码,比讲理论直观得多。

对象适配器示例(Java)

// 目标接口:新系统期望的接口
public interface NewSystem {
    String processData(String input);
}

// 适配者:老系统的实现
public class LegacySystem {
    public String handleRequest(String xmlData) {
        // 老系统只处理 XML
        return "<response>OK</response>";
    }
}

// 适配器:把老系统包装成新系统
public class LegacyAdapter implements NewSystem {
    private LegacySystem legacy;

    public LegacyAdapter(LegacySystem legacy) {
        this.legacy = legacy;
    }

    @Override
    public String processData(String input) {
        // 1. 把 JSON 转成 XML
        String xmlInput = convertJsonToXml(input);
        // 2. 调用老系统
        String xmlOutput = legacy.handleRequest(xmlInput);
        // 3. 把 XML 转回 JSON
        return convertXmlToJson(xmlOutput);
    }

    private String convertJsonToXml(String json) {
        // 实际转换逻辑
        return "<request>" + json + "</request>";
    }

    private String convertXmlToJson(String xml) {
        // 实际转换逻辑
        return "{ \"status\": \"OK\" }";
    }
}

你看,新系统调用 processData,完全不知道背后是个老古董在干活。适配器把脏活累活全扛了。

我的习惯:适配器里不要塞业务逻辑。它只做格式转换和接口映射。业务逻辑一进去,适配器就变成了「四不像」,后期维护会非常痛苦。

类适配器示例(Java)

// 类适配器:通过继承实现
public class ClassAdapter extends LegacySystem implements NewSystem {
    @Override
    public String processData(String input) {
        String xmlInput = convertJsonToXml(input);
        String xmlOutput = handleRequest(xmlInput);  // 直接调用父类方法
        return convertXmlToJson(xmlOutput);
    }
    // 转换方法同上
}

类适配器代码更少,但 Java 单继承的限制让它不够灵活。我一般只在适配逻辑非常简单时才用。

对比维度 对象适配器 类适配器
实现方式 组合(持有适配者引用) 继承(继承适配者类)
灵活性 高,可适配多个适配者 低,只能适配一个父类
耦合度 低,面向接口编程 高,依赖具体父类
我推荐 ✅ 优先使用 ⚠️ 谨慎使用

1.3 接口适配的常见场景

场景太多了。我挑几个最典型的说说。

场景一:第三方 SDK 集成

每个第三方支付、推送、地图 SDK 都有自己的接口风格。你不可能让业务代码去适配每个 SDK。加一层适配器,业务只跟你的抽象接口打交道。换 SDK 时,只改适配器,不动业务。

我曾经在一个电商项目里,对接过四家物流公司。每家接口都不一样。我写了个 LogisticsAdapter,统一成 createShipment()、trackOrder() 几个方法。后来换物流商,两天就搞定了。

场景二:旧系统迁移

老系统跑得好好的,但接口太老旧。新系统要接进来,又不敢动老代码。适配器就是最好的「中间人」。我在金融项目里干过这事——核心账务系统是 2005 年的 C++ 写的,新风控系统是 Java。适配器扛了两年,直到老系统彻底下线。

场景三:多数据源统一查询

公司有 MySQL、Redis、Elasticsearch,查询方式各不相同。业务层希望一个 search(keyword) 搞定所有。适配器模式正好用上:每个数据源一个适配器,统一返回标准结果集。

避坑指南:我曾经在适配器里做了数据聚合和排序,结果性能惨不忍睹。适配器只做接口适配,不做数据加工。数据聚合是服务层的活,别混在一起。

1.4 适配器模式的核心结构图

下面这张图,是我画了无数遍的。你把它记牢,适配器模式就懂了八成。

适配器模式核心结构图 适配器模式核心结构 Client(调用方) <<接口>> Target Adapter(适配器) Adaptee(适配者) 调用 实现 持有引用 💡 核心流程: 1. Client 面向 Target 接口编程,不知道 Adaptee 的存在 2. Adapter 实现 Target 接口,内部持有 Adaptee 的引用 3. Adapter 把 Client 的请求「翻译」成 Adaptee 能理解的调用

这张图你多看两眼。Client 只认识 Target 接口,Adapter 实现了 Target,背后调用 Adaptee。这就是适配器模式的全部秘密。

1.5 什么时候不该用适配器

适配器虽好,但不是万能药。我见过不少滥用的情况。

  • 接口差异太大:两边语义完全不同,硬适配只会让代码变得诡异。这时候该重构就重构。
  • 性能敏感路径:适配器多了一层调用和转换,高频场景下可能成为瓶颈。我曾经在网关层用适配器做协议转换,QPS 一上去就扛不住,后来改成直接解析。
  • 可以改源码时:如果两边代码都是你的,直接改接口比加适配器更干净。适配器是为「不能改」的场景准备的。

我的判断标准:问自己一个问题——「半年后别人看这段代码,能一眼明白为什么加适配器吗?」如果答案是否定的,那可能选错了方案。