设计模式 | 适配器模式

发布于:2025-06-29 ⋅ 阅读:(19) ⋅ 点赞:(0)

适配器模式(Adapter Pattern) 是结构型设计模式中的连接器大师,它允许不兼容接口的类能够协同工作。本文将深入探索适配器模式的核心思想、实现技巧以及在C++中的高效实践,解决现实开发中的接口兼容性问题。

为什么需要适配器模式

在软件开发中,我们经常遇到接口不兼容的情况:

  • 遗留系统与现代框架的集成

  • 第三方库与自有系统的对接

  • 不同子系统之间的数据交换

  • API升级导致的接口变更

直接修改已有代码通常不可行:

  • 第三方库无法修改

  • 旧系统代码难以重构

  • 新老系统需要并行运行

  • 修改可能引入新错误

适配器模式通过创建中间转换层解决了这些问题,成为系统集成的关键桥梁。

适配器模式的核心概念

模式结构解析

[客户端] --> [目标接口]
                  ↑
           [适配器] ---> [被适配者]

关键角色定义

  1. 目标接口(Target)

    • 客户端期望的接口

  2. 被适配者(Adaptee)

    • 需要适配的现有组件

  3. 适配器(Adapter)

    • 转换接口的中间件

    • 实现目标接口

    • 包装被适配者

C++实现:电源适配器系统

让我们通过电源适配器系统展示适配器模式的实际应用:

#include <iostream>
#include <memory>
#include <cmath>
#include <iomanip>

// ================ 目标接口:现代电源标准 ================
class ModernPowerOutlet {
public:
    virtual ~ModernPowerOutlet() = default;
    
    // 输出标准USB-C电源
    virtual void supplyPower() const = 0;
    
    // 获取电源规格
    virtual void getSpecs() const {
        std::cout << "标准: USB-C PD 3.1\n";
        std::cout << "电压: 5V-48V\n";
        std::cout << "功率: 最高240W\n";
    }
};

// ================ 被适配者:旧式电源接口 ================
class LegacyPowerOutlet {
public:
    // 旧式交流电源输出
    void outputACPower(int voltage, int current) const {
        std::cout << "输出交流电: " << voltage << "V, " << current << "A\n";
    }
    
    // 获取旧式电源规格
    void showLegacySpecs() const {
        std::cout << "=== 旧式电源规格 ===\n";
        std::cout << "类型: 交流电\n";
        std::cout << "电压: 110V/220V\n";
        std::cout << "频率: 50/60Hz\n";
    }
};

// ================ 类适配器(多重继承) ================
class PowerClassAdapter : public ModernPowerOutlet, private LegacyPowerOutlet {
public:
    void supplyPower() const override {
        std::cout << "转换交流到直流...\n";
        // 调用被适配者的方法
        outputACPower(220, 5); 
        std::cout << "输出: USB-C 20V/5A (100W)\n";
    }
    
    void getSpecs() const override {
        ModernPowerOutlet::getSpecs();
        std::cout << "适配器类型: 类适配器\n";
        showLegacySpecs();
    }
};

// ================ 对象适配器(组合方式) ================
class PowerObjectAdapter : public ModernPowerOutlet {
public:
    // 通过构造函数注入被适配对象
    explicit PowerObjectAdapter(LegacyPowerOutlet* outlet) 
        : legacyOutlet_(outlet) {}
    
    void supplyPower() const override {
        std::cout << "转换交流到直流...\n";
        // 调用被适配者的方法
        legacyOutlet_->outputACPower(220, 5);
        std::cout << "输出: USB-C 20V/5A (100W)\n";
    }
    
    void getSpecs() const override {
        ModernPowerOutlet::getSpecs();
        std::cout << "适配器类型: 对象适配器\n";
        legacyOutlet_->showLegacySpecs();
    }

private:
    LegacyPowerOutlet* legacyOutlet_;
};

// ================ 客户端代码 ================
void chargeDevice(ModernPowerOutlet* outlet) {
    std::cout << "\n=== 开始充电 ===\n";
    outlet->getSpecs();
    outlet->supplyPower();
    std::cout << "设备充电中...\n";
    std::cout << "=== 充电完成 ===\n";
}

int main() {
    // 创建被适配对象
    LegacyPowerOutlet legacyOutlet;
    
    // 使用类适配器
    std::cout << "===== 使用类适配器 =====\n";
    PowerClassAdapter classAdapter;
    chargeDevice(&classAdapter);
    
    // 使用对象适配器
    std::cout << "\n\n===== 使用对象适配器 =====\n";
    PowerObjectAdapter objectAdapter(&legacyOutlet);
    chargeDevice(&objectAdapter);
    
    return 0;
}

适配器模式的两种实现方式

1. 类适配器(继承方式)

class ClassAdapter : public Target, private Adaptee {
public:
    void request() override {
        // 转换并调用被适配者的方法
        specificRequest();
    }
};

特点

  • 使用多重继承

  • 适配器继承目标接口和被适配者

  • 静态绑定,编译时确定

  • 可能违反单一职责原则

2. 对象适配器(组合方式)

class ObjectAdapter : public Target {
public:
    ObjectAdapter(Adaptee* adaptee) : adaptee_(adaptee) {}
    
    void request() override {
        // 转换并调用被适配者的方法
        adaptee_->specificRequest();
    }

private:
    Adaptee* adaptee_;
};

特点

  • 使用对象组合

  • 更灵活,支持运行时适配

  • 符合合成复用原则

  • 可以适配多个对象

  • 现代C++更推荐的方式

适配器模式的高级应用

1. 双向适配器

class BiDirectionalAdapter : public NewInterface, public OldInterface {
public:
    BiDirectionalAdapter(OldSystem* old, NewSystem* newSys) 
        : oldSystem_(old), newSystem_(newSys) {}
    
    // 实现新接口
    void newMethod() override {
        oldSystem_->legacyMethod();
    }
    
    // 实现旧接口
    void legacyMethod() override {
        newSystem_->newMethod();
    }

private:
    OldSystem* oldSystem_;
    NewSystem* newSystem_;
};

2. 参数适配器

class FunctionAdapter {
public:
    using NewSignature = void(int, double);
    
    explicit FunctionAdapter(std::function<void(std::string, float)> oldFunc)
        : oldFunc_(oldFunc) {}
    
    void operator()(int a, double b) {
        // 转换参数并调用旧函数
        oldFunc_(std::to_string(a), static_cast<float>(b));
    }

private:
    std::function<void(std::string, float)> oldFunc_;
};

// 使用
void legacyPrint(std::string s, float f) {
    std::cout << s << " : " << f << "\n";
}

int main() {
    FunctionAdapter adapter(legacyPrint);
    adapter(42, 3.14); // 自动转换参数类型
}

3. STL中的适配器

#include <vector>
#include <stack>
#include <queue>
#include <functional>

// 容器适配器示例
std::stack<int> s;              // deque适配为栈
std::queue<double> q;           // deque适配为队列
std::priority_queue<int> pq;    // vector适配为优先队列

// 函数对象适配器
auto negate = std::negate<int>();
auto plus10 = std::bind(std::plus<int>(), std::placeholders::_1, 10);
auto isEven = [](int x) { return x % 2 == 0; };
auto isOdd = std::not1(std::function<bool(int)>(isEven));

适配器模式的现实应用场景

1. 图形渲染接口适配

// OpenGL接口
class OpenGLRenderer {
public:
    void glClearColor(float r, float g, float b, float a) {
        std::cout << "OpenGL: 设置清除颜色 (" << r << ", " << g << ", " << b << ", " << a << ")\n";
    }
    // 其他OpenGL方法...
};

// Vulkan接口适配器
class VulkanToOpenGLAdapter : public OpenGLRenderer {
public:
    void vkCmdClearColor(float r, float g, float b, float a) {
        // 将Vulkan命令转换为OpenGL调用
        glClearColor(r, g, b, a);
    }
    // 其他适配方法...
};

2. 支付系统集成

// 统一支付接口
class PaymentProcessor {
public:
    virtual void processPayment(double amount, const std::string& currency) = 0;
};

// PayPal适配器
class PayPalAdapter : public PaymentProcessor {
public:
    PayPalAdapter(PayPalService* paypal) : paypal_(paypal) {}
    
    void processPayment(double amount, const std::string& currency) override {
        // 转换到PayPal要求的格式
        paypal_->sendPayment(amount * 100, currency + "_MICRO");
    }

private:
    PayPalService* paypal_;
};

// Stripe适配器
class StripeAdapter : public PaymentProcessor {
public:
    void processPayment(double amount, const std::string& currency) override {
        stripe::Charge::create({
            {"amount", static_cast<int>(amount * 100)},
            {"currency", currency}
        });
    }
};

3. 传感器数据标准化

// 统一传感器接口
class Sensor {
public:
    virtual double read() const = 0;
    virtual std::string getUnit() const = 0;
};

// 温度传感器适配器
class TemperatureAdapter : public Sensor {
public:
    TemperatureAdapter(LegacyThermometer* thermo) : thermo_(thermo) {}
    
    double read() const override {
        // 华氏度转摄氏度
        return (thermo_->getFahrenheit() - 32) * 5/9;
    }
    
    std::string getUnit() const override {
        return "°C";
    }

private:
    LegacyThermometer* thermo_;
};

// 压力传感器适配器
class PressureAdapter : public Sensor {
public:
    PressureAdapter(BarometricSensor* sensor) : sensor_(sensor) {}
    
    double read() const override {
        // mmHg转hPa
        return sensor_->getmmHg() * 1.33322;
    }
    
    std::string getUnit() const override {
        return "hPa";
    }

private:
    BarometricSensor* sensor_;
};

适配器模式的五大优势

  1. 接口兼容性

    // 旧接口
    void legacyPrint(int x, float y);
    
    // 新接口适配器
    class PrinterAdapter {
    public:
        void print(double a, double b) {
            legacyPrint(static_cast<int>(a), static_cast<float>(b));
        }
    };
  2. 代码复用

    // 复用现有实现
    class NewServiceAdapter : public NewServiceInterface {
    public:
        NewServiceAdapter(OldService* service) : service_(service) {}
        
        void newMethod() override {
            service_->oldMethod(); // 复用旧实现
        }
    };
  3. 解耦系统

    // 客户端只依赖抽象接口
    void clientCode(DataProcessor* processor) {
        processor->process(data);
    }
    
    // 适配不同实现
    clientCode(new XMLProcessorAdapter(xmlParser));
    clientCode(new JSONProcessorAdapter(jsonParser));
  4. 增量迁移

    // 逐步替换旧系统
    class HybridSystem : public NewSystem {
    public:
        HybridSystem(OldSystem* old) : oldAdapter_(old) {}
        
        void newOperation() override {
            if (useOldSystem) {
                oldAdapter_.legacyOperation();
            } else {
                NewSystem::newOperation();
            }
        }
    };
  5. 多平台支持

    // 跨平台文件系统适配
    class FileSystemAdapter {
    public:
        #ifdef _WIN32
            WindowsFileSys winFS;
        #elif __APPLE__
            MacFileSys macFS;
        #elif __linux__
            LinuxFileSys linuxFS;
        #endif
        
        std::string readFile(const std::string& path) {
            #ifdef _WIN32
                return winFS.readWinFile(path);
            #elif __APPLE__
                return macFS.readMacFile(path);
            // ...
            #endif
        }
    };

适配器模式的最佳实践

1. 优先使用对象适配器

// 更灵活,支持运行时配置
class FlexibleAdapter : public Target {
public:
    FlexibleAdapter(Adaptee* adaptee) : adaptee_(adaptee) {}
    
    // 实现目标接口...
    
private:
    Adaptee* adaptee_; // 组合优于继承
};

2. 使用智能指针管理资源

class SafeAdapter : public Target {
public:
    SafeAdapter(std::shared_ptr<Adaptee> adaptee) 
        : adaptee_(std::move(adaptee)) {}
    
    // 实现目标接口...

private:
    std::shared_ptr<Adaptee> adaptee_;
};

// 使用
auto adaptee = std::make_shared<LegacyComponent>();
SafeAdapter adapter(adaptee);

3. 保持适配器轻量级

// 只包含必要的转换逻辑
class MinimalAdapter : public NewInterface {
public:
    MinimalAdapter(OldComponent* comp) : comp_(comp) {}
    
    void newMethod() override {
        // 只做必要转换
        comp_->oldMethod();
    }
    
    // 不实现不需要的方法
};

4. 适配器命名规范

// 清晰表达适配关系
class LegacyToModernAdapter   // 旧系统到新系统
class XMLToJSONAdapter       // XML到JSON转换
class FahrenheitToCelsiusAdapter // 温度单位转换
class PayPalPaymentAdapter   // PayPal支付适配

适配器模式与其他模式的关系

模式 关系 区别
装饰器模式 都使用包装 装饰器添加功能,适配器转换接口
外观模式 都简化接口 外观定义新接口,适配器复用现有接口
桥接模式 都解耦抽象与实现 桥接预先设计,适配器事后补救
代理模式 都使用间接访问 代理控制访问,适配器转换接口

组合使用示例

// 适配器 + 工厂模式
class PaymentAdapterFactory {
public:
    static PaymentProcessor* createAdapter(PaymentType type) {
        switch (type) {
            case PAYPAL: return new PayPalAdapter(new PayPalService);
            case STRIPE: return new StripeAdapter;
            case CRYPTO: return new CryptoPaymentAdapter;
            default: throw std::invalid_argument("不支持的支付类型");
        }
    }
};

// 客户端代码
auto processor = PaymentAdapterFactory::createAdapter(PAYPAL);
processor->processPayment(99.99, "USD");

应用案例

1. 数据库访问层适配

// 统一数据库接口
class Database {
public:
    virtual void execute(const std::string& query) = 0;
};

// MySQL适配器
class MySQLAdapter : public Database {
public:
    MySQLAdapter(MySQLConn* conn) : conn_(conn) {}
    
    void execute(const std::string& query) override {
        conn_->mysql_exec(query.c_str());
    }
};

// PostgreSQL适配器
class PostgresAdapter : public Database {
public:
    void execute(const std::string& query) override {
        PGresult* res = PQexec(conn_, query.c_str());
        // 处理结果...
    }
};

// SQLite适配器
class SQLiteAdapter : public Database {
public:
    void execute(const std::string& query) override {
        sqlite3_exec(db_, query.c_str(), nullptr, nullptr, nullptr);
    }
};

2. 日志系统集成

// 统一日志接口
class Logger {
public:
    virtual void log(LogLevel level, const std::string& message) = 0;
};

// Log4cpp适配器
class Log4cppAdapter : public Logger {
public:
    Log4cppAdapter(log4cpp::Category* cat) : category_(cat) {}
    
    void log(LogLevel level, const std::string& msg) override {
        switch (level) {
            case DEBUG: category_->debug(msg); break;
            case INFO: category_->info(msg); break;
            case WARN: category_->warn(msg); break;
            case ERROR: category_->error(msg); break;
        }
    }
};

// Boost.Log适配器
class BoostLogAdapter : public Logger {
public:
    void log(LogLevel level, const std::string& msg) override {
        switch (level) {
            case DEBUG: BOOST_LOG_TRIVIAL(debug) << msg; break;
            case INFO: BOOST_LOG_TRIVIAL(info) << msg; break;
            case WARN: BOOST_LOG_TRIVIAL(warning) << msg; break;
            case ERROR: BOOST_LOG_TRIVIAL(error) << msg; break;
        }
    }
};

3. 跨平台UI框架

// 统一UI组件接口
class UIButton {
public:
    virtual void render(int x, int y, int width, int height) = 0;
};

// Windows按钮适配器
class WinButtonAdapter : public UIButton {
public:
    void render(int x, int y, int w, int h) override {
        HWND button = CreateWindow("BUTTON", "Click", 
                                  WS_VISIBLE | WS_CHILD,
                                  x, y, w, h, parent, NULL, NULL, NULL);
    }
};

// macOS按钮适配器
class MacButtonAdapter : public UIButton {
public:
    void render(int x, int y, int w, int h) override {
        NSButton* button = [[NSButton alloc] initWithFrame:NSMakeRect(x, y, w, h)];
        [button setTitle:@"Click"];
        [parent addSubview:button];
    }
};

// Linux按钮适配器
class LinuxButtonAdapter : public UIButton {
public:
    void render(int x, int y, int w, int h) override {
        GtkWidget* button = gtk_button_new_with_label("Click");
        gtk_fixed_put(GTK_FIXED(container), button, x, y);
        gtk_widget_set_size_request(button, w, h);
    }
};

适配器模式的挑战与解决方案

挑战 解决方案
接口差异过大 使用双向适配器或中间抽象层
适配器过多导致混乱 使用工厂模式管理适配器创建
性能开销 优化转换逻辑,缓存常用结果
链式适配问题 避免多层嵌套,使用组合适配器

性能优化示例

class CachingAdapter : public Target {
public:
    void request() override {
        if (!cached) {
            result = adaptee_->computeExpensiveOperation();
            cached = true;
        }
        // 使用缓存结果
        processResult(result);
    }
};

总结

适配器模式是解决接口不兼容问题的终极武器,它通过:

  1. 无缝集成:连接不兼容的接口

  2. 代码复用:利用现有实现

  3. 解耦系统:减少组件间依赖

  4. 增量演进:支持系统逐步迁移

  5. 标准化接口:统一多样化实现

使用时机

  • 需要使用现有类但其接口不符合需求

  • 需要创建可复用的类与不相关类协同工作

  • 需要集成多个第三方库提供统一接口

  • 旧系统迁移过程中需要与新系统共存

"适配器模式不是修改齿轮的齿形,而是在齿轮间添加传动装置。它是面向对象设计中解决接口兼容问题的优雅方案。" - 设计模式实践者


网站公告

今日签到

点亮在社区的每一天
去签到