23种设计模式 - 适配器模式(Adapter)

适配器模式(Adapter)------ 转接头大法

大白话解释

你现在有两样东西:

一个是你现在系统要用的接口(标准)

一个是别人给你的老东西(不符合标准)

这俩对不上,直接用不了

怎么办?

👉 中间加一层"翻译官"

你说:"给我 info()"

翻译官转头说:"老系统,用 level=1 写日志!"

适配器模式:你不用改老代码,也不用改新系统,中间帮你"翻译一下"就能用了。

常见场景:

  • 老系统接口对接新系统(遗留代码改造)
  • 第三方库接口不符合项目规范
  • 数据格式转换(XML 转 JSON)
  • 日志库适配

核心思路

  1. 目标接口:调用方期望的接口
  2. 被适配者:已有的、不兼容的类
  3. 适配器:包装被适配者,实现目标接口

C++ 代码示例

场景:新系统用的是 Logger 接口,但公司有个老的日志库只有 OldFileLogger,接口不一样。用适配器让老库接入新系统。

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

// ==============================
// 目标接口:新系统期望的日志接口
// ==============================
class Logger {
public:
    virtual ~Logger() = default;
    virtual void info(const std::string& msg) = 0;
    virtual void warn(const std::string& msg) = 0;
    virtual void error(const std::string& msg) = 0;
};

// ==============================
// 被适配者:老的第三方日志库
// 我们无法修改它的代码!
// ==============================
class OldFileLogger {
public:
    void writeLog(int level, const std::string& content) {
        std::string levelStr;
        switch (level) {
            case 1: levelStr = "INFO"; break;
            case 2: levelStr = "WARN"; break;
            case 3: levelStr = "ERROR"; break;
            default: levelStr = "UNKNOWN";
        }
        std::cout << "[OldFileLogger][" << levelStr << "] " << content << "\n";
    }
};

// ==============================
// 对象适配器(推荐):组合方式
// ==============================
class OldLoggerAdapter : public Logger {
private:
    std::shared_ptr<OldFileLogger> oldLogger; // 持有老系统实例

public:
    OldLoggerAdapter(std::shared_ptr<OldFileLogger> logger)
        : oldLogger(logger) {}

    void info(const std::string& msg) override {
        oldLogger->writeLog(1, msg); // 翻译:info -> level 1
    }

    void warn(const std::string& msg) override {
        oldLogger->writeLog(2, msg); // 翻译:warn -> level 2
    }

    void error(const std::string& msg) override {
        oldLogger->writeLog(3, msg); // 翻译:error -> level 3
    }
};

// ==============================
// 另一个例子:类适配器(继承方式)
// ==============================
class AnotherOldSystem {
public:
    void printMessage(const std::string& msg) {
        std::cout << "[AnotherSystem] >>> " << msg << "\n";
    }
};

// 类适配器:同时继承目标接口和被适配者
class ClassAdapter : public Logger, private AnotherOldSystem {
public:
    void info(const std::string& msg) override {
        printMessage("INFO: " + msg);
    }
    void warn(const std::string& msg) override {
        printMessage("WARN: " + msg);
    }
    void error(const std::string& msg) override {
        printMessage("ERROR: " + msg);
    }
};

// ==============================
// 业务代码:只依赖 Logger 接口
// ==============================
class UserService {
private:
    std::shared_ptr<Logger> logger;

public:
    UserService(std::shared_ptr<Logger> log) : logger(log) {}

    void login(const std::string& username) {
        logger->info("用户登录: " + username);
    }

    void loginFailed(const std::string& username) {
        logger->warn("登录失败: " + username);
    }

    void criticalError(const std::string& msg) {
        logger->error("严重错误: " + msg);
    }
};

int main() {
    std::cout << "=== 使用对象适配器接入老日志库 ===\n";
    auto oldLogger = std::make_shared<OldFileLogger>();
    auto adapter = std::make_shared<OldLoggerAdapter>(oldLogger);

    UserService service1(adapter);
    service1.login("张三");
    service1.loginFailed("黑客");
    service1.criticalError("数据库连接失败");

    std::cout << "\n=== 使用类适配器接入另一个老系统 ===\n";
    auto classAdapter = std::make_shared<ClassAdapter>();
    UserService service2(classAdapter);
    service2.login("李四");
    service2.criticalError("磁盘空间不足");

    return 0;
}

输出:

复制代码
=== 使用对象适配器接入老日志库 ===
[OldFileLogger][INFO] 用户登录: 张三
[OldFileLogger][WARN] 登录失败: 黑客
[OldFileLogger][ERROR] 严重错误: 数据库连接失败

=== 使用类适配器接入另一个老系统 ===
[AnotherSystem] >>> INFO: 用户登录: 李四
[AnotherSystem] >>> ERROR: 严重错误: 磁盘空间不足

两种适配器对比

对象适配器 类适配器
实现方式 组合(持有被适配者实例) 多继承
灵活性 高(运行时可换) 低(编译期固定)
适用 推荐,C++ 多继承虽支持但复杂 简单场景

优缺点

说明
✅ 优点 复用已有代码,不改原类
✅ 优点 单一职责:转换逻辑集中在适配器
❌ 缺点 有时候适配器层太多会变复杂
❌ 缺点 不如直接修改原代码直接(但有时候不能改)

一句话记忆

适配器模式 = 不改旧东西、不改新接口,中间加个"翻译层",让两边能对话。

相关推荐
qq_2975746714 小时前
设计模式系列文章(基础篇第 11 篇):模板方法模式——定义算法骨架,实现代码复用与流程统一
算法·设计模式·模板方法模式
狂人开飞机19 小时前
01. 工厂模式(Factory Pattern)
设计模式·c#
阿狸猿20 小时前
论软件设计模式及其应用
设计模式
workflower20 小时前
具身智能-三层结构
人工智能·设计模式·动态规划·软件工程·scrum
我爱cope21 小时前
【Agent智能体10 | 反思设计模式-AI数据分析的可视化实战】
人工智能·设计模式·数据分析
老码观察21 小时前
设计模式实战解读(七):适配器模式——让不兼容的接口无缝协作
java·设计模式·适配器模式
人月神话-Lee2 天前
【图像处理】框架设计——协议、值类型与工程化思维
图像处理·人工智能·ios·设计模式·架构·ai编程·swift
AI大法师2 天前
Xbox回归经典绿
大数据·设计模式·xbox
老码观察2 天前
设计模式实战解读(六):装饰器模式——功能增强,不动原代码
java·设计模式·装饰器模式