将一个类的接口转换成客户端期望的另一个接口。适配器使得原本因接口不兼容而无法一起工作的类可以协同工作。
生活类比:出国旅行的转换插头:手机充电器只认「pay(元)」,Stripe 要「charge(分)」,PayPal 要「美元」。适配器在中间换单位、改方法名,收银台毫无感知。
flowchart LR
classDef client fill:#C2E5FF,stroke:#007AD2,color:#1E1E1E
classDef abs fill:#DCCCFF,stroke:#874FFF,color:#1E1E1E
classDef concrete fill:#CDF4D3,stroke:#3E9B4B,color:#1E1E1E
classDef extra fill:#FFE0C2,stroke:#EB7500,color:#1E1E1E
classDef shared fill:#FFECBD,stroke:#E8A302,color:#1E1E1E
classDef hub fill:#C6FAF6,stroke:#5AD8CC,color:#1E1E1E
cashier["收银台 checkout 只认 pay 元"]
subgraph plugs ["转换插头 适配器"]
sa["Stripe 适配器 元变分"]
pa["PayPal 适配器 元变美元"]
end
stripe["Stripe SDK charge 分"]
paypal["PayPal SDK send_payment 美元"]
cashier ==> sa --> stripe
cashier ==> pa --> paypal
class cashier client
class sa,pa extra
class stripe,paypal concrete
style plugs fill:#FFE0C2,stroke:#EB7500
| 图中角色 | 本仓库示例 |
|---|---|
| 收银台 | checkout,只依赖 PaymentProcessor |
| 转换插头 | StripeAdapter / PayPalAdapter |
| 异形插座 | StripePayment / PayPalPayment 第三方 SDK |
23 张图的完整图鉴见 docs/README.md。
- 想使用一个已存在的类,但它的接口不符合系统需要(如接入第三方 SDK)
- 需要复用一些现存的子类,但不可能对每一个都进行接口改造
- 多个类接口不一致,需要统一到同一套抽象下
PaymentProcessor::pay(yuan) 是应用统一的目标接口;第三方 StripePayment::charge_in_cents(cents) 是不兼容的被适配者。StripeAdapter 同时持有 StripePayment 引用并实现 PaymentProcessor,在内部完成单位换算:
class StripeAdapter : public PaymentProcessor {
public:
explicit StripeAdapter(StripePayment& stripe) : stripe_(stripe) {}
void pay(double yuan) override { // 元 -> 分,再转调第三方接口
stripe_.charge_in_cents(std::llround(yuan * 100));
}
private:
StripePayment& stripe_;
};客户端 checkout(PaymentProcessor&, amount) 只认识 pay(yuan),既能对接原生实现,也能透明地对接经过适配的第三方 SDK。
| 文件 | 说明 |
|---|---|
payment.h |
目标接口 PaymentProcessor、被适配者 StripePayment、适配器 StripeAdapter、对照组 NativeAlipay |
payment.cpp |
各类的具体实现 |
main.cpp |
用同一个 checkout() 函数分别结算原生实现与适配后的第三方实现 |
Makefile |
编译与运行 |
make # 编译
make run # 编译并运行
make clean # 清理=== 适配器模式:统一支付接口 ===
发起结算,金额 99.9 元:
[支付宝原生接口] 直接扣款 99.9 元
发起结算,金额 199.5 元:
[适配器] 收到 pay(199.5) 元,转换为分后转调 Stripe 接口
[Stripe 原始接口] charge_in_cents(19950) -> 扣款 19950 分
- 对象适配器(组合)优于类适配器(多继承) — 本示例用组合持有
StripePayment&,避免 C++ 多继承的复杂性 - 单一职责 — 适配逻辑(单位换算)集中在
StripeAdapter一处,不污染业务代码 - 客户端无感知 —
checkout()只依赖PaymentProcessor抽象接口,不知道也不需要知道是否经过适配 - 对已有代码零侵入 — 不需要修改
StripePayment这一“第三方代码”即可接入系统