适配器模式(Adapter Pattern)

C++ 适配器模式(Adapter Pattern)


1. 模式定义与核心思想

适配器模式(Adapter Pattern)结构型设计模式 ,用于将不兼容的接口转换成客户端期望的接口,让原本无法协同工作的类可以一起工作。

别名:Wrapper(包装器)

核心一句话

加一层中间转换,不改旧代码、不改新接口,让两者兼容。

现实类比

电源插头转换器:设备用国标插头 → 适配器 → 美标插座。


2. 解决的核心痛点

  • 第三方库/旧系统接口与当前系统不匹配
  • 遗留代码无法修改,但必须接入新系统
  • 多平台、多服务、多SDK接口不统一
  • 重构时需要渐进式兼容,不能一刀切
  • 希望统一调用风格,屏蔽底层差异

传统方案问题

  • 直接改源码:第三方/旧代码不能动
  • 到处写转换:重复、混乱、难维护
  • 重写实现:成本高、风险大

3. 模式四大角色

角色 职责
Target(目标接口) 客户端期望使用的接口
Adaptee(被适配者) 已存在、但接口不兼容的类
Adapter(适配器) 实现 Target,包装 Adaptee,做转换
Client(客户端) 面向 Target 编程,使用适配器

调用流程

Client → Target 接口 → Adapter → Adaptee


4. 两种实现方式(C++ 必掌握)

4.1 类适配器(继承实现)

  • 方式:公有继承 Target,私有继承 Adaptee
  • C++ 依赖多重继承
  • 编译期绑定,灵活性较低
cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 目标接口(客户端期望)
class Target {
public:
    virtual ~Target() = default;
    virtual void request(const string& msg) = 0;
};

// 被适配者(旧接口/第三方)
class Adaptee {
public:
    void specificRequest(const char* msg) {
        cout << "[Adaptee] " << msg << endl;
    }
};

// 类适配器:继承 + 转换
class ClassAdapter : public Target, private Adaptee {
public:
    void request(const string& msg) override {
        // 接口转换
        specificRequest(msg.c_str());
    }
};

4.2 对象适配器(组合实现)【工程首选】

  • 方式:继承 Target,组合 Adaptee 指针/引用
  • 符合组合优于继承
  • 运行时可切换被适配者,支持适配多个
cpp 复制代码
// 对象适配器
class ObjectAdapter : public Target {
private:
    Adaptee* adaptee_;  // 组合被适配者
public:
    ObjectAdapter(Adaptee* adaptee) : adaptee_(adaptee) {}

    void request(const string& msg) override {
        adaptee_->specificRequest(msg.c_str());
    }
};

4.3 两种适配器对比

特性 类适配器 对象适配器
实现 多重继承 组合
耦合
灵活性 编译期固定 运行可切换
适配多对象
重写方法 不可
推荐 ⭐⭐⭐ ⭐⭐⭐⭐⭐

5. C++ 完整工程示例(统一支付系统)

场景

旧支付接口、微信支付、支付宝接口不统一,需要对外提供统一支付接口

cpp 复制代码
// ==================== 目标接口(统一支付) ====================
class Payment {
public:
    virtual ~Payment() = default;
    virtual bool pay(int amount, const string& user) = 0;
};

// ==================== 被适配者1:旧美元支付 ====================
class OldPayment {
public:
    bool payInDollar(double amount) {
        cout << "旧系统支付:$" << amount << endl;
        return true;
    }
};

// ==================== 被适配者2:微信支付 ====================
class WeChatPay {
public:
    bool doPay(string userId, int money) {
        cout << "微信支付:用户" << userId << " 支付" << money << "元" << endl;
        return true;
    }
};

// ==================== 被适配者3:支付宝 ====================
class AliPay {
public:
    bool payTo(string account, int cash) {
        cout << "支付宝:账户" << account << " 支付" << cash << "元" << endl;
        return true;
    }
};

// ==================== 适配器1:旧支付适配 ====================
class OldPaymentAdapter : public Payment {
private:
    OldPayment* oldPay_;
public:
    OldPaymentAdapter(OldPayment* p) : oldPay_(p) {}
    bool pay(int amount, const string&) override {
        return oldPay_->payInDollar(amount / 7.0);
    }
};

// ==================== 适配器2:微信适配 ====================
class WeChatAdapter : public Payment {
private:
    WeChatPay* wx_;
public:
    WeChatAdapter(WeChatPay* p) : wx_(p) {}
    bool pay(int amount, const string& user) override {
        return wx_->doPay(user, amount);
    }
};

// ==================== 适配器3:支付宝适配 ====================
class AliPayAdapter : public Payment {
private:
    AliPay* ali_;
public:
    AliPayAdapter(AliPay* p) : ali_(p) {}
    bool pay(int amount, const string& user) override {
        return ali_->payTo(user, amount);
    }
};

使用示例

cpp 复制代码
int main() {
    // 客户端只面向统一接口 Payment
    Payment* p1 = new OldPaymentAdapter(new OldPayment());
    Payment* p2 = new WeChatAdapter(new WeChatPay());
    Payment* p3 = new AliPayAdapter(new AliPay());

    p1->pay(700, "user001");
    p2->pay(100, "user001");
    p3->pay(200, "user002");
    return 0;
}

6. 适配器模式经典应用(C++ 标准库)

C++ STL 内置大量容器适配器,是适配器模式最佳示范:

  • stack(底层可使用 deque/vector/list)
  • queue
  • priority_queue

示例:

cpp 复制代码
#include <stack>
#include <vector>
using namespace std;

// stack 是适配器,底层用 vector
stack<int, vector<int>> st;
st.push(1);
st.pop();

7. 适用场景

✅ 第三方库/SDK 接口不兼容

✅ 旧系统、遗留代码需要接入新架构

✅ 多平台 API 差异需要统一

✅ 统一多个相似服务的接口(支付、消息、存储)

✅ 架构重构、渐进式迁移、兼容过渡

✅ 简化复杂接口,提供易用包装


8. 优点

  1. 不修改原有代码,符合开闭原则
  2. 单一职责:只做接口转换
  3. 解耦:客户端不依赖被适配者
  4. 高复用:复用已有类,不重复造轮子
  5. 灵活扩展:新增适配只需加适配器类

9. 缺点

  1. 增加额外类,系统复杂度略微提升
  2. 多层转换可能轻微影响性能
  3. 接口差异过大时不适合(应重构而非适配)

10. C++ 开发最佳实践

  1. 优先使用对象适配器(组合 > 继承)
  2. 适配器只做转换,不写业务逻辑
  3. 智能指针管理被适配者生命周期
  4. 适配多个同类服务时,可搭配工厂模式创建适配器
  5. 转换逻辑集中、清晰、可测试
  6. 不要为了适配而适配:接口差异巨大应优先重构

11. 常见坑点与避坑

  1. 类适配器滥用多重继承
    → 优先对象适配器
  2. 适配器写业务逻辑
    → 违反单一职责
  3. 被适配者生命周期失控
    → 使用 unique_ptr/shared_ptr
  4. 过度适配
    → 接口差异大应重构

12. 面试高频题(标准答案)

Q1:适配器模式作用?

将不兼容接口转换为目标接口,不改原有代码,让新旧系统/第三方服务协同工作。

Q2:类适配器 vs 对象适配器区别?

类适配器用多重继承 ;对象适配器用组合,更灵活、松耦合、工程首选。

Q3:适配器模式体现哪些设计原则?

  • 单一职责
  • 开闭原则
  • 组合优于继承
  • 依赖倒置

Q4:什么时候不用适配器?

接口差异巨大、底层逻辑不匹配,应重构而非适配。

Q5:STL 中哪些是适配器?

stack、queue、priority_queue 都是容器适配器。


13. 适配器在架构中的地位

  • 防腐层(ACL):隔离第三方/外部系统污染领域模型
  • 微服务网关:统一接口格式
  • 跨平台层:屏蔽 Windows/Linux 差异
  • 新旧系统迁移:无痛过渡
相关推荐
吴声子夜歌1 小时前
Java——接口的细节
java·开发语言·算法
阿拉金alakin1 小时前
深入理解 Java 锁机制:CAS 原理、synchronized 优化与主流锁策略全总结
java·开发语言
myheartgo-on1 小时前
Java—方 法
java·开发语言·算法·青少年编程
雨落在了我的手上1 小时前
如何学习java?
java·开发语言·学习
范什么特西2 小时前
计算机杂记
java
RyFit2 小时前
SpirngAI
java
庞轩px2 小时前
第六篇:Spring用了哪些设计模式?——从单例到代理,拆解框架中的经典设计
java·spring·设计模式·bean·代理模式·aop·单例
宝贝儿好2 小时前
【LLM】第三章:项目实操案例:智能输入法项目
人工智能·python·深度学习·算法·机器人
番石榴AI3 小时前
纯 CPU 推理!0.1B 超轻量级端到端OCR模型,使用 Java 进行文档解析
java·开发语言·ocr