当甲方说"我全都要":适配器模式的兼容魔法

82 阅读5分钟

前言

当我们遇到了什么都想要的甲方, 希望把各个平台的功能都集成到系统里, 这是我们就可以使用适配器模式来实现。

适配器模式:让不兼容的接口协同工作

意图

解决两个已有组件接口不兼容但需要协作的问题,通过创建中间转换层(适配器)使原本不兼容的接口能够协同工作。如同现实中的电源转换器,让不同标准的插头适配到目标插座。

问题

假如你正在开发一款股票市场监测程序, 它会从不同来源下载 XML 格式的股票数据, 然后向用户呈现出美观的图表。

在开发过程中, 你决定在程序中整合一个第三方智能分析函数库。 但是遇到了一个问题, 那就是分析函数库只兼容 JSON 格式的数据。

你可以修改程序库来支持 XML。 但是, 这可能需要修改部分依赖该程序库的现有代码。 甚至还有更糟糕的情况, 你可能根本没有程序库的源代码, 从而无法对其进行修改。

解决方案

你可以创建一个适配器。 这是一个特殊的对象, 能够转换对象接口, 使其能与其他对象进行交互。

适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。

适配器不仅可以转换不同格式的数据, 其还有助于采用不同接口的对象之间的合作。 它的运作方式如下:

  • 适配器实现与其中一个现有对象兼容的接口。
  • 现有对象可以使用该接口安全地调用适配器方法。
  • 适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象。

有时你甚至可以创建一个双向适配器来实现双向转换调用。

让我们回到股票市场程序。 为了解决数据格式不兼容的问题, 你可以为分析函数库中的每个类创建将 XML 转换为 JSON 格式的适配器, 然后让客户端仅通过这些适配器来与函数库进行交流。 当某个适配器被调用时, 它会将传入的 XML 数据转换为 JSON 结构, 并将其传递给被封装分析对象的相应方法。

现实场景类比

国际旅行时遇到的美标(两扁脚)插头与欧标(两圆脚)插座不兼容问题。电源适配器作为中间转换装置,将美标插头的形状转换为欧标插座支持的形态,同时保持电力传输的核心功能。

模式结构

模式的UML图

代码示例

// 旧版文件读取接口
class LegacyFileReader {
    public byte[] readFileBytes(String path) {
        // 实现字节读取逻辑
        return new byte[0];
    }
}

// 目标接口(新系统要求)
interface FileContentReader {
    String readContent(String path);
}

// 适配器实现
class FileReaderAdapter implements FileContentReader {
    private LegacyFileReader legacyReader;

    public FileReaderAdapter(LegacyFileReader reader) {
        this.legacyReader = reader;
    }

    @Override
    public String readContent(String path) {
        byte[] bytes = legacyReader.readFileBytes(path);
        return new String(bytes).trim(); // 转换为字符串处理
    }
}

// 使用示例
public class Client {
    public static void main(String[] args) {
        LegacyFileReader legacy = new LegacyFileReader();
        FileContentReader reader = new FileReaderAdapter(legacy);
        System.out.println(reader.readContent("data.txt"));
    }
}

适合场景

  • 系统升级时整合遗留代码
  • 需要使用第三方库但接口不匹配
  • 需要统一多个类的不一致接口
  • 希望复用现有类但接口不符合需求
  • 临时解决方案(在重构前过渡使用)

实现步骤

  1. 识别不兼容接口:明确目标接口(客户端期望的)和被适配接口
  2. 创建目标接口:定义客户端需要的统一方法签名
  3. 实现适配器类
    • 实现目标接口
    • 添加被适配者的引用(组合方式)
    • 在目标接口方法中调用被适配者的方法
  4. 选择适配方式
    • 对象适配器(推荐):通过构造函数传入被适配对象
    • 类适配器:继承被适配类(Java需使用继承+实现接口)
  5. 客户端调用:通过目标接口使用适配器
  6. 测试验证:确保适配转换逻辑正确

优缺点

优点

  • 符合开闭原则,无需修改已有代码
  • 提高代码复用性
  • 增强系统扩展性
  • 解耦客户端与被适配者

缺点

  • 增加系统复杂性(额外中间层)
  • 过多使用会降低代码可读性
  • 类适配器需要多重继承(Java无法直接支持)

与其他模式的关系

  • 桥接模式:关注抽象与实现的分离,适配器侧重接口转换
  • 装饰者模式:增强功能不改变接口,适配器改变接口
  • 外观模式:简化复杂子系统接口,适配器做接口转换
  • 代理模式:控制访问保持接口相同,适配器改变接口

最佳实践建议:优先使用对象适配器方式,当需要同时适配多个类时可考虑类适配器。注意不要过度使用,在系统设计阶段应优先考虑接口的统一性。

最后

如果文章对你有帮助,点个免费的赞鼓励一下吧!关注gzh:加瓦点灯, 每天推送干货知识!