跳到主要内容
设计模式实战:C++ 装饰者模式与适配器模式的应用 | 极客日志
C++ Pay 算法
设计模式实战:C++ 装饰者模式与适配器模式的应用 C++ 中装饰者模式与适配器模式的核心思想及实现细节。通过电商订单优惠系统和支付网关案例,展示了如何利用装饰者模式动态扩展对象功能,避免继承导致的类爆炸;利用适配器模式解决接口不兼容问题,实现第三方库集成。内容涵盖角色划分、代码示例、智能指针管理、优缺点分析及避坑指南,帮助开发者在实际业务场景中灵活运用两种结构型设计模式,构建灵活可扩展的系统架构。
设计模式实战:C++ 中装饰者模式与适配器模式的应用
本章学习目标与重点
掌握装饰者模式的核心设计思想、角色划分及 C++ 实现细节(动态扩展功能、避免继承臃肿)
理解适配器模式的两种实现方式(类适配器、对象适配器)及适用场景
能够结合实际业务场景(如功能增强、接口兼容)灵活运用两种模式
解决模式应用中的关键问题(如装饰者层级管理、适配器接口匹配、类型转换安全)
重点: 装饰者模式的动态扩展逻辑、适配器模式的接口适配技巧、两种模式的组合使用场景
设计模式进阶认知:结构型模式的核心价值
在 C++ 开发中,结构型设计模式专注于解决'类与对象的组合方式'问题,通过合理的结构组合,实现功能复用、接口兼容或功能扩展。相比行为型模式关注'对象交互',结构型模式更侧重'对象组装'。
为什么需要结构型设计模式?
实际开发中,我们常遇到以下结构相关的问题:
需为一个对象动态添加额外功能(如给商品订单添加优惠券、积分抵扣、满减等功能),若使用继承会导致类数量爆炸;
现有类的接口与目标接口不匹配(如第三方库的接口格式与项目现有接口不一致),直接使用会导致代码耦合严重;
类的功能过于复杂,需拆分但又不想破坏原有接口;
希望复用多个类的功能,但又不能通过多重继承实现(避免菱形继承、代码冗余)。
结构型模式通过标准化的组合方式,将'核心功能'与'扩展功能''现有接口'与'目标接口'分离,例如装饰者模式通过组合实现功能动态扩展,适配器模式通过转换实现接口兼容,从而解决上述问题。
结构型模式的核心设计原则
结构型模式的设计始终围绕以下原则展开,这也是本章两种模式的核心指导思想:
合成复用原则:优先使用对象组合,而非类继承,实现功能复用(减少耦合、提升灵活性);
开放 - 封闭原则:扩展功能时无需修改原有代码,通过新增类实现;
接口隔离原则:适配或扩展时,不依赖不必要的接口,保持接口简洁;
依赖倒置原则:依赖抽象接口,不依赖具体实现(如装饰者与被装饰者依赖同一抽象)。
装饰者模式:动态扩展对象功能的灵活方案
装饰者模式(Decorator Pattern)又称包装器模式(Wrapper Pattern),其核心思想是'动态地给一个对象添加一些额外的职责,就像在墙上刷油漆一样,不改变对象本身的结构,却能增强其功能'。
核心角色与设计逻辑
1. 核心角色
抽象组件(Component):定义被装饰对象和装饰者的共同接口,是装饰者模式的基础;
具体组件(ConcreteComponent):被装饰的核心对象,实现抽象组件接口,包含核心功能;
抽象装饰者(Decorator):继承自抽象组件,持有一个抽象组件的引用,定义装饰者的统一接口;
具体装饰者(ConcreteDecorator):实现抽象装饰者接口,通过调用被装饰对象的方法,再添加额外功能。
2. 设计逻辑
抽象装饰者与具体组件继承自同一抽象组件,确保装饰者与被装饰者类型一致,可相互替换;抽象装饰者持有抽象组件的引用,通过组合方式将装饰者与被装饰者关联,实现'装饰者包裹被装饰者'的嵌套结构,从而动态添加功能。
适用场景
需动态为对象添加或移除功能(如订单支付时,根据用户选择动态添加优惠券、积分抵扣等);
避免使用继承导致的类爆炸(如一个核心功能有多种扩展功能,组合方式多样);
扩展功能需灵活组合(如商品可以同时享受'折扣 + 优惠券 + 满减'多重优惠);
不希望修改原有类的代码(符合开放 - 封闭原则)。
基础实现:电商订单优惠系统(C++ 示例)
以'电商订单优惠系统'为例:订单(具体组件)可享受多种优惠(具体装饰者),如优惠券抵扣、积分抵扣、满减优惠,且优惠可灵活组合(如同时使用优惠券 + 积分),使用装饰者模式可动态扩展优惠功能。
步骤 1:定义抽象组件(订单接口)
#include
std;
{
:
= ;
= ;
~ () {}
};
<iostream>
#include <string>
using
namespace
class
OrderComponent
public
virtual float CalculateFinalPrice () const
0
virtual string GetOrderDescription () const
0
virtual
OrderComponent
步骤 2:实现具体组件(基础订单)
class BasicOrder : public OrderComponent {
private :
string orderId;
float originalPrice;
public :
BasicOrder (const string& id, float price) : orderId (id), originalPrice (price) {
if (price < 0 ) {
throw invalid_argument ("商品原价不能为负数!" );
}
}
float CalculateFinalPrice () const override {
return originalPrice;
}
string GetOrderDescription () const override {
return "订单 [" + orderId + "] 基础价格:" + to_string (originalPrice) + "元" ;
}
float GetOriginalPrice () const {
return originalPrice;
}
};
步骤 3:定义抽象装饰者(优惠装饰器接口)
class DiscountDecorator : public OrderComponent {
private :
OrderComponent* component;
protected :
OrderComponent* GetComponent () const {
return component;
}
public :
DiscountDecorator (OrderComponent* comp) : component (comp) {
if (comp == nullptr ) {
throw invalid_argument ("被装饰的订单组件不能为空!" );
}
}
~DiscountDecorator () {}
float CalculateFinalPrice () const override {
return component->CalculateFinalPrice ();
}
string GetOrderDescription () const override {
return component->GetOrderDescription ();
}
};
步骤 4:实现具体装饰者(各种优惠)
class CouponDecorator : public DiscountDecorator {
private :
float couponAmount;
public :
CouponDecorator (OrderComponent* comp, float amount) : DiscountDecorator (comp), couponAmount (amount) {
if (amount <= 0 ) {
throw invalid_argument ("优惠券金额必须大于 0!" );
}
}
float CalculateFinalPrice () const override {
float basePrice = GetComponent ()->CalculateFinalPrice ();
float finalPrice = basePrice - couponAmount;
return finalPrice < 0 ? 0 : finalPrice;
}
string GetOrderDescription () const override {
return GetComponent ()->GetOrderDescription () + " + 优惠券抵扣" + to_string (couponAmount) + "元" ;
}
};
class PointsDecorator : public DiscountDecorator {
private :
int points;
public :
PointsDecorator (OrderComponent* comp, int pts) : DiscountDecorator (comp), points (pts) {
if (pts <= 0 ) {
throw invalid_argument ("抵扣积分必须大于 0!" );
}
}
float CalculateFinalPrice () const override {
float basePrice = GetComponent ()->CalculateFinalPrice ();
float discountAmount = points / 100.0f ;
float finalPrice = basePrice - discountAmount;
return finalPrice < 0 ? 0 : finalPrice;
}
string GetOrderDescription () const override {
return GetComponent ()->GetOrderDescription () + " + " + to_string (points) + "积分抵扣" + to_string (points / 100.0f ) + "元" ;
}
};
class FullReduceDecorator : public DiscountDecorator {
private :
float fullAmount;
float reduceAmount;
public :
FullReduceDecorator (OrderComponent* comp, float full, float reduce) : DiscountDecorator (comp), fullAmount (full), reduceAmount (reduce) {
if (full <= 0 || reduce <= 0 ) {
throw invalid_argument ("满减门槛和减免金额必须大于 0!" );
}
if (reduce >= full) {
throw invalid_argument ("减免金额不能大于等于满减门槛!" );
}
}
float CalculateFinalPrice () const override {
float basePrice = GetComponent ()->CalculateFinalPrice ();
float finalPrice = basePrice;
if (basePrice >= fullAmount) {
finalPrice = basePrice - reduceAmount;
}
return finalPrice < 0 ? 0 : finalPrice;
}
string GetOrderDescription () const override {
return GetComponent ()->GetOrderDescription () + " + 满" + to_string (fullAmount) + "减" + to_string (reduceAmount) + "元" ;
}
};
步骤 5:客户端使用示例(灵活组合优惠) int main () {
try {
OrderComponent* basicOrder = new BasicOrder ("ORD20240502001" , 1500.0f );
cout << "=== 基础订单 ===" << endl;
cout << basicOrder->GetOrderDescription () << endl;
cout << "最终价格:" << basicOrder->CalculateFinalPrice () << "元" << endl;
OrderComponent* couponOrder = new CouponDecorator (basicOrder, 200.0f );
cout << "\n=== 基础订单 + 优惠券 ===" << endl;
cout << couponOrder->GetOrderDescription () << endl;
cout << "最终价格:" << couponOrder->CalculateFinalPrice () << "元" << endl;
OrderComponent* couponPointsOrder = new PointsDecorator (couponOrder, 500 );
cout << "\n=== 基础订单 + 优惠券 + 积分 ===" << endl;
cout << couponPointsOrder->GetOrderDescription () << endl;
cout << "最终价格:" << couponPointsOrder->CalculateFinalPrice () << "元" << endl;
OrderComponent* fullReduceOrder = new FullReduceDecorator (couponPointsOrder, 1000.0f , 150.0f );
cout << "\n=== 基础订单 + 优惠券 + 积分 + 满减 ===" << endl;
cout << fullReduceOrder->GetOrderDescription () << endl;
cout << "最终价格:" << fullReduceOrder->CalculateFinalPrice () << "元" << endl;
OrderComponent* onlyFullReduceOrder = new FullReduceDecorator (basicOrder, 1000.0f , 150.0f );
cout << "\n=== 基础订单 + 满减 ===" << endl;
cout << onlyFullReduceOrder->GetOrderDescription () << endl;
cout << "最终价格:" << onlyFullReduceOrder->CalculateFinalPrice () << "元" << endl;
delete fullReduceOrder;
delete couponPointsOrder;
delete couponOrder;
delete onlyFullReduceOrder;
delete basicOrder;
} catch (const exception& e) {
cout << "错误:" << e.what () << endl;
}
return 0 ;
}
运行结果 === 基础订单 === 订单 [ORD20240502001] 基础价格:1500.000000 元 最终价格:1500 元
=== 基础订单 + 优惠券 === 订单 [ORD20240502001] 基础价格:1500.000000 元 + 优惠券抵扣 200.000000 元 最终价格:1300 元
=== 基础订单 + 优惠券 + 积分 === 订单 [ORD20240502001] 基础价格:1500.000000 元 + 优惠券抵扣 200.000000 元 + 500 积分抵扣 5.000000 元 最终价格:1295 元
=== 基础订单 + 优惠券 + 积分 + 满减 === 订单 [ORD20240502001] 基础价格:1500.000000 元 + 优惠券抵扣 200.000000 元 + 500 积分抵扣 5.000000 元 + 满 1000 减 150.000000 元 最终价格:1145 元
=== 基础订单 + 满减 === 订单 [ORD20240502001] 基础价格:1500.000000 元 + 满 1000 减 150.000000 元 最终价格:1350 元
进阶优化:智能指针管理与多层装饰增强 基础实现中,手动管理装饰者层级的内存容易出错(如遗漏释放、重复释放),且装饰者功能相对简单。以下优化方案使用智能指针自动管理内存,并新增'限时折扣'装饰者,支持更复杂的多层嵌套。
优化 1:使用智能指针管理内存 #include <memory>
int main () {
try {
shared_ptr<OrderComponent> basicOrder = make_shared <BasicOrder>("ORD20240502002" , 2000.0f );
shared_ptr<OrderComponent> couponOrder = make_shared <CouponDecorator>(basicOrder.get (), 300.0f );
shared_ptr<OrderComponent> discountOrder = make_shared <DiscountDecorator>(couponOrder.get (), [](float basePrice) { return basePrice * 0.9f ; });
shared_ptr<OrderComponent> fullReduceOrder = make_shared <FullReduceDecorator>(discountOrder.get (), 1500.0f , 200.0f );
cout << "=== 智能指针管理:多层优惠组合 ===" << endl;
cout << fullReduceOrder->GetOrderDescription () << endl;
cout << "最终价格:" << fullReduceOrder->CalculateFinalPrice () << "元" << endl;
} catch (const exception& e) {
cout << "错误:" << e.what () << endl;
}
return 0 ;
}
优化 2:新增'限时折扣'装饰者(支持动态折扣率)
class TimeLimitDiscountDecorator : public DiscountDecorator {
private :
float discountRate;
public :
TimeLimitDiscountDecorator (OrderComponent* comp, float rate) : DiscountDecorator (comp), discountRate (rate) {
if (rate <= 0 || rate >= 1 ) {
throw invalid_argument ("折扣率必须在 (0,1) 之间!" );
}
}
float CalculateFinalPrice () const override {
float basePrice = GetComponent ()->CalculateFinalPrice ();
return basePrice * discountRate;
}
string GetOrderDescription () const override {
return GetComponent ()->GetOrderDescription () + " + 限时" + to_string (discountRate * 10 ) + "折" ;
}
void SetDiscountRate (float rate) {
if (rate <= 0 || rate >= 1 ) {
throw invalid_argument ("折扣率必须在 (0,1) 之间!" );
}
discountRate = rate;
}
};
int main () {
shared_ptr<OrderComponent> basicOrder = make_shared <BasicOrder>("ORD20240502003" , 1000.0f );
shared_ptr<TimeLimitDiscountDecorator> timeLimitOrder = make_shared <TimeLimitDiscountDecorator>(basicOrder.get (), 0.9f );
cout << "=== 限时折扣测试 ===" << endl;
cout << timeLimitOrder->GetOrderDescription () << endl;
cout << "9 折后价格:" << timeLimitOrder->CalculateFinalPrice () << "元" << endl;
timeLimitOrder->SetDiscountRate (0.8f );
cout << "\n修改为 8 折后:" << endl;
cout << timeLimitOrder->GetOrderDescription () << endl;
cout << "8 折后价格:" << timeLimitOrder->CalculateFinalPrice () << "元" << endl;
return 0 ;
}
优化后运行结果 === 限时折扣测试 === 订单 [ORD20240502003] 基础价格:1000.000000 元 + 限时 9.000000 折 9 折后价格:900 元
修改为 8 折后:订单 [ORD20240502003] 基础价格:1000.000000 元 + 限时 8.000000 折 8 折后价格:800 元
装饰者模式的优缺点与避坑指南
优点
动态扩展功能:无需修改原有代码,通过新增装饰者即可扩展功能,符合开放 - 封闭原则;
功能组合灵活:多个装饰者可嵌套组合,实现复杂功能(如优惠券 + 积分 + 满减);
替代继承减少类爆炸:避免为每个功能组合创建单独的子类;
保持接口一致性:装饰者与被装饰者继承自同一抽象接口,可无缝替换。
缺点
层级嵌套复杂:多层装饰者嵌套后,调试和理解难度增加;
内存管理复杂:手动管理时需按层级释放资源,容易出现内存泄漏或重复释放;
仅适用于同一抽象接口:装饰者与被装饰者必须依赖同一抽象组件,否则无法装饰。
避坑指南
使用智能指针管理内存:优先使用 shared_ptr 自动管理装饰者和被装饰对象的生命周期,避免手动释放错误;
控制装饰者层级:避免过度嵌套(建议不超过 3 层),复杂组合可通过'复合装饰者'简化;
明确装饰顺序:不同装饰顺序可能导致结果不同,需在业务中明确规则;
抽象组件接口简洁:抽象组件只定义核心接口,避免冗余方法,降低装饰者实现成本。
适配器模式:接口兼容的桥梁方案 适配器模式(Adapter Pattern)的核心思想是'将一个类的接口转换成客户希望的另一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作'。
核心角色与实现方式
1. 核心角色
目标接口(Target):客户期望的接口,适配器将其他接口转换为该接口;
适配者(Adaptee):现有需要适配的接口(如第三方库接口、旧系统接口);
适配器(Adapter):实现目标接口,同时持有适配者的引用(或继承适配者),将目标接口的调用转换为适配者接口的调用。
2. 两种实现方式
类适配器:适配器继承自适配者和目标接口(多重继承),通过继承获取适配者的功能,实现目标接口供客户端调用;
对象适配器:适配器实现目标接口,同时持有适配者的对象引用(组合方式),通过委托调用适配者的功能。
实战建议: C++ 中优先使用对象适配器 ,避免多重继承带来的菱形继承、二义性等问题,且组合方式更灵活,支持适配多个适配者。
适用场景
集成第三方库:第三方库的接口与项目现有接口不匹配,需适配后使用;
旧系统改造:旧系统的接口无法修改,但新系统需要使用其功能;
接口标准化:多个类的功能相同但接口不同,需统一为目标接口;
复用现有类:现有类功能满足需求,但接口不符合客户端要求。
实现方式 1:对象适配器(推荐) 以'第三方支付接口适配'为例:项目现有支付接口(目标接口)要求 Pay(float amount) 方法,而引入的第三方支付库(适配者)的接口为 DoPayment(float money, string orderId),使用对象适配器将第三方接口转换为项目所需接口。
步骤 1:定义目标接口(项目现有支付接口) #include <iostream>
#include <string>
using namespace std;
class PaymentTarget {
public :
virtual bool Pay (float amount) = 0 ;
virtual string GetPaymentName () const = 0 ;
virtual ~PaymentTarget () {}
};
步骤 2:定义适配者(第三方支付库接口)
class ThirdPartyPayment {
public :
bool DoPayment (float money, const string& orderId) {
cout << "第三方支付库执行支付:订单 ID=" << orderId << ",金额=" << money << "元" << endl;
return true ;
}
string QueryPaymentStatus (const string& orderId) {
return "订单" + orderId + "支付成功" ;
}
};
步骤 3:实现对象适配器(转换接口)
class PaymentAdapter : public PaymentTarget {
private :
ThirdPartyPayment* adaptee;
string orderId;
public :
PaymentAdapter (ThirdPartyPayment* adapteeObj, const string& id) : adaptee (adapteeObj), orderId (id) {
if (adapteeObj == nullptr ) {
throw invalid_argument ("适配者对象不能为空!" );
}
}
~PaymentAdapter () {
}
bool Pay (float amount) override {
if (amount <= 0 ) {
cout << "支付金额必须大于 0!" << endl;
return false ;
}
return adaptee->DoPayment (amount, orderId);
}
string GetPaymentName () const override {
return "第三方支付(适配器转换)" ;
}
string QueryStatus () {
return adaptee->QueryPaymentStatus (orderId);
}
};
步骤 4:客户端使用示例
void ProcessPayment (PaymentTarget* payment, float amount) {
cout << "=== 执行支付 ===" << endl;
cout << "支付方式:" << payment->GetPaymentName () << endl;
bool success = payment->Pay (amount);
if (success) {
cout << "支付成功!" << endl;
} else {
cout << "支付失败!" << endl;
}
}
int main () {
try {
ThirdPartyPayment* thirdPartyPay = new ThirdPartyPayment ();
PaymentAdapter* adapter = new PaymentAdapter (thirdPartyPay, "ORD20240503001" );
ProcessPayment (adapter, 899.0f );
cout << "\n查询支付状态:" << adapter->QueryStatus () << endl;
delete adapter;
delete thirdPartyPay;
} catch (const exception& e) {
cout << "错误:" << e.what () << endl;
}
return 0 ;
}
运行结果 === 执行支付 === 支付方式:第三方支付(适配器转换) 第三方支付库执行支付:订单 ID =ORD20240503001,金额=899 元 支付成功! 查询支付状态:订单 ORD20240503001 支付成功
实现方式 2:类适配器(多重继承) 同样以'第三方支付接口适配'为例,使用类适配器实现(继承适配者和目标接口):
步骤 1-2:目标接口和适配者与对象适配器一致
步骤 3:实现类适配器
class PaymentClassAdapter : public PaymentTarget, public ThirdPartyPayment {
private :
string orderId;
public :
PaymentClassAdapter (const string& id) : orderId (id) {}
bool Pay (float amount) override {
if (amount <= 0 ) {
cout << "支付金额必须大于 0!" << endl;
return false ;
}
return DoPayment (amount, orderId);
}
string GetPaymentName () const override {
return "第三方支付(类适配器)" ;
}
string QueryStatus () {
return QueryPaymentStatus (orderId);
}
};
步骤 4:客户端使用示例 int main () {
PaymentClassAdapter* classAdapter = new PaymentClassAdapter ("ORD20240503002" );
ProcessPayment (classAdapter, 1299.0f );
cout << "\n查询支付状态:" << classAdapter->QueryStatus () << endl;
delete classAdapter;
return 0 ;
}
运行结果 === 执行支付 === 支付方式:第三方支付(类适配器) 第三方支付库执行支付:订单 ID =ORD20240503002,金额=1299 元 支付成功! 查询支付状态:订单 ORD20240503002 支付成功
两种适配器实现的对比 对比维度 类适配器 对象适配器 实现方式 多重继承(目标接口 + 适配者) 组合(实现目标接口 + 持有适配者引用) 灵活性 差:只能适配特定适配者,无法适配其子类 好:可适配适配者及其子类,支持多个适配者 耦合度 高:与适配者类强耦合 低:与适配者接口弱耦合 扩展能力 差:新增适配者需修改或新增适配器 好:可通过构造函数传入不同适配者 访问适配者方法 直接访问(继承) 间接访问(委托) 适用场景 适配者类稳定,无子类扩展 适配者可能有子类,需灵活适配
实战结论: 对象适配器在灵活性、低耦合度上优势明显,是 C++ 开发中的首选方案;类适配器仅适用于适配者类稳定、无扩展需求的简单场景。
适配器模式的优缺点与避坑指南
优点
解决接口不兼容问题:使原本无法协作的类可以一起工作(如第三方库与项目接口);
复用现有功能:无需修改现有类(适配者)的代码,直接复用其功能;
透明性:客户端只依赖目标接口,无需知道适配者的存在,降低代码耦合;
灵活性高:对象适配器支持适配多个适配者,可动态切换适配者。
缺点
增加系统复杂度:新增适配器类会增加代码量,降低系统可读性;
适配逻辑复杂:若目标接口与适配者接口差异较大,适配器的转换逻辑会非常复杂;
性能损耗:适配器的委托调用会带来轻微的性能损耗(可忽略不计)。
避坑指南
明确适配边界:适配器只负责接口转换,不添加额外业务逻辑(避免适配器职责过重);
避免过度适配:若目标接口与适配者接口差异过大(如需要大量转换逻辑),应考虑重构接口,而非使用适配器;
优先适配接口而非实现:适配器依赖适配者的接口,而非具体实现,确保适配者替换时适配器仍可用;
结合工厂模式:使用工厂模式创建适配器,客户端无需关心适配器的创建细节,提升代码可维护性。
实战案例:结合装饰者模式与适配器模式开发支付网关系统
需求分析
支持多种支付方式(微信支付、支付宝支付、第三方支付库),且支付接口统一(目标接口 Pay(float amount));
支付过程需动态添加额外功能(如日志记录、签名验证、支付结果回调);
第三方支付库的接口与统一接口不兼容,需适配后使用;
支持支付方式和额外功能的灵活扩展(如新增银联支付、新增风控校验功能);
客户端只需调用统一接口,无需关心具体支付方式和扩展功能的实现。
设计思路
适配器模式:将第三方支付库、微信支付、支付宝支付的接口适配为统一支付接口(PaymentTarget);
装饰者模式:为统一支付接口动态添加日志记录、签名验证、回调通知等扩展功能;
组合设计:适配器封装具体支付方式的接口,装饰者包裹适配器(或基础支付类),实现'接口统一 + 功能扩展'的双重目标。
完整实现代码 #include <iostream>
#include <string>
#include <memory>
#include <ctime>
using namespace std;
class PaymentTarget {
public :
virtual bool Pay (float amount) = 0 ;
virtual string GetPaymentName () const = 0 ;
virtual ~PaymentTarget () {}
};
class WeChatPayment : public PaymentTarget {
public :
bool Pay (float amount) override {
cout << "[微信支付] 发起支付请求,金额:" << amount << "元" << endl;
return true ;
}
string GetPaymentName () const override {
return "微信支付" ;
}
};
class AlipayPayment : public PaymentTarget {
public :
bool Pay (float amount) override {
cout << "[支付宝支付] 发起支付请求,金额:" << amount << "元" << endl;
return true ;
}
string GetPaymentName () const override {
return "支付宝支付" ;
}
};
class ThirdPartyPayLib {
public :
bool ExecutePay (const string& orderNo, double money, const string& token) {
cout << "[第三方支付库] 订单号:" << orderNo << ",金额:" << money << "元,token:" << token << endl;
return true ;
}
string GetPayResult (const string& orderNo) {
return "第三方支付成功,订单号:" + orderNo;
}
};
class ThirdPartyPayAdapter : public PaymentTarget {
private :
shared_ptr<ThirdPartyPayLib> adaptee;
string orderNo;
string token;
public :
ThirdPartyPayAdapter (const string& no, const string& tk) : orderNo (no), token (tk) {
adaptee = make_shared <ThirdPartyPayLib>();
}
bool Pay (float amount) override {
if (amount <= 0 ) return false ;
return adaptee->ExecutePay (orderNo, amount, token);
}
string GetPaymentName () const override {
return "第三方支付(适配器)" ;
}
string QueryPayResult () {
return adaptee->GetPayResult (orderNo);
}
};
class PaymentDecorator : public PaymentTarget {
private :
shared_ptr<PaymentTarget> component;
protected :
shared_ptr<PaymentTarget> GetComponent () const {
return component;
}
public :
PaymentDecorator (shared_ptr<PaymentTarget> comp) : component (comp) {
if (!component) throw invalid_argument ("支付组件不能为空!" );
}
bool Pay (float amount) override {
return component->Pay (amount);
}
string GetPaymentName () const override {
return component->GetPaymentName ();
}
};
class LogPaymentDecorator : public PaymentDecorator {
public :
LogPaymentDecorator (shared_ptr<PaymentTarget> comp) : PaymentDecorator (comp) {}
bool Pay (float amount) override {
time_t now = time (nullptr );
cout << "[支付日志] " << ctime (&now) << " 开始支付,方式:" << GetComponent ()->GetPaymentName () << ",金额:" << amount << "元" << endl;
bool success = GetComponent ()->Pay (amount);
cout << "[支付日志] 支付结果:" << (success ? "成功" : "失败" ) << endl;
return success;
}
string GetPaymentName () const override {
return GetComponent ()->GetPaymentName () + "(带日志)" ;
}
};
class SignaturePaymentDecorator : public PaymentDecorator {
private :
string appSecret;
public :
SignaturePaymentDecorator (shared_ptr<PaymentTarget> comp, const string& secret) : PaymentDecorator (comp), appSecret (secret) {}
bool Pay (float amount) override {
cout << "[签名验证] 正在验证签名,appSecret:" << appSecret << endl;
bool verifySuccess = true ;
if (!verifySuccess) {
cout << "[签名验证] 签名失败,支付终止!" << endl;
return false ;
}
cout << "[签名验证] 签名成功,继续支付..." << endl;
return GetComponent ()->Pay (amount);
}
string GetPaymentName () const override {
return GetComponent ()->GetPaymentName () + "(带签名验证)" ;
}
};
class CallbackPaymentDecorator : public PaymentDecorator {
private :
string callbackUrl;
public :
CallbackPaymentDecorator (shared_ptr<PaymentTarget> comp, const string& url) : PaymentDecorator (comp), callbackUrl (url) {}
bool Pay (float amount) override {
bool success = GetComponent ()->Pay (amount);
if (success) {
cout << "[回调通知] 向" << callbackUrl << "发送支付成功回调" << endl;
} else {
cout << "[回调通知] 向" << callbackUrl << "发送支付失败回调" << endl;
}
return success;
}
string GetPaymentName () const override {
return GetComponent ()->GetPaymentName () + "(带回调)" ;
}
};
class PaymentGateway {
public :
static bool ProcessPayment (shared_ptr<PaymentTarget> payment, float amount) {
cout << "\n==================== 支付网关 ====================" << endl;
cout << "支付方式:" << payment->GetPaymentName () << endl;
cout << "支付金额:" << amount << "元" << endl;
bool success = payment->Pay (amount);
cout << "==================================================" << endl;
return success;
}
};
int main () {
try {
shared_ptr<PaymentTarget> wechatPay = make_shared <WeChatPayment>();
wechatPay = make_shared <LogPaymentDecorator>(wechatPay);
wechatPay = make_shared <SignaturePaymentDecorator>(wechatPay, "wechat_secret_123" );
wechatPay = make_shared <CallbackPaymentDecorator>(wechatPay, "https://api.example.com/wechat/callback" );
PaymentGateway::ProcessPayment (wechatPay, 699.0f );
shared_ptr<PaymentTarget> thirdPartyPay = make_shared <ThirdPartyPayAdapter>("ORDER_20240504_001" , "token_abc123" );
thirdPartyPay = make_shared <LogPaymentDecorator>(thirdPartyPay);
thirdPartyPay = make_shared <CallbackPaymentDecorator>(thirdPartyPay, "https://api.example.com/thirdparty/callback" );
PaymentGateway::ProcessPayment (thirdPartyPay, 1599.0f );
shared_ptr<PaymentTarget> alipay = make_shared <AlipayPayment>();
PaymentGateway::ProcessPayment (alipay, 399.0f );
class UnionPayPayment : public PaymentTarget {
public :
bool Pay (float amount) override {
cout << "[银联支付] 发起支付请求,金额:" << amount << "元" << endl;
return true ;
}
string GetPaymentName () const override {
return "银联支付" ;
}
};
shared_ptr<PaymentTarget> unionPay = make_shared <UnionPayPayment>();
unionPay = make_shared <LogPaymentDecorator>(unionPay);
PaymentGateway::ProcessPayment (unionPay, 899.0f );
} catch (const exception& e) {
cout << "支付网关错误:" << e.what () << endl;
}
return 0 ;
}
代码说明与运行效果
核心设计亮点
适配器模式解决接口兼容:第三方支付库通过适配器转换为统一支付接口,与微信支付、支付宝支付无缝集成;
装饰者模式实现功能扩展:日志、签名、回调等功能通过装饰者动态添加,支持灵活组合(如'日志 + 签名''日志 + 回调');
客户端无感知:支付网关提供统一接口,客户端无需关心具体支付方式和扩展功能的实现,只需传入封装后的支付对象;
扩展性强:新增支付方式只需实现 PaymentTarget 接口,新增扩展功能只需新增装饰者类,无需修改现有核心代码。
运行结果(关键片段) ==================== 支付网关 ==================== 支付方式:微信支付(带日志)(带签名验证)(带回调) 支付金额:699 元 [支付日志] Wed May 4 10:00:00 2024 开始支付,方式:微信支付(带签名验证)(带回调),金额:699 元 [签名验证] 正在验证签名,appSecret:wechat_secret_123 [签名验证] 签名成功,继续支付... [微信支付] 发起支付请求,金额:699 元 [回调通知] 向 https://api.example.com/wechat/callback 发送支付成功回调 [支付日志] 支付结果:成功 ================================================== ==================== 支付网关 ==================== 支付方式:第三方支付(适配器)(带日志)(带回调) 支付金额:1599 元 [支付日志] Wed May 4 10:00:00 2024 开始支付,方式:第三方支付(适配器)(带回调),金额:1599 元 [第三方支付库] 订单号:ORDER_20240504_001,金额:1599 元,token:token_abc123 [回调通知] 向 https://api.example.com/thirdparty/callback 发送支付成功回调 [支付日志] 支付结果:成功 ================================================== ==================== 支付网关 ==================== 支付方式:支付宝支付 支付金额:399 元 [支付宝支付] 发起支付请求,金额:399 元 ================================================== ==================== 支付网关 ==================== 支付方式:银联支付(带日志) 支付金额:899 元 [支付日志] Wed May 4 10:00:00 2024 开始支付,方式:银联支付,金额:899 元 [银联支付] 发起支付请求,金额:899 元 [支付日志] 支付结果:成功 ==================================================
本章总结 本章重点讲解了 C++ 开发中常用的两种结构型设计模式:装饰者模式和适配器模式,核心要点总结如下:
装饰者模式 :
核心价值:动态扩展对象功能,避免继承导致的类爆炸;
关键实现:抽象组件定义统一接口,抽象装饰者持有组件引用,具体装饰者添加额外功能;
核心优势:功能组合灵活、符合开放 - 封闭原则、保持接口一致性;
适用场景:动态添加/移除功能、功能组合多样、不修改原有代码扩展功能。
适配器模式 :
核心价值:解决接口不兼容问题,使不同接口的类可以协同工作;
两种实现:对象适配器(组合方式,推荐)、类适配器(多重继承,慎用);
核心优势:复用现有功能、透明适配、低耦合、灵活性高;
适用场景:集成第三方库、旧系统改造、接口标准化、复用现有类。
模式组合技巧 :
装饰者 + 适配器:适配器统一接口,装饰者扩展功能(如支付网关案例);
装饰者 + 工厂模式:工厂创建基础组件,装饰者动态添加功能,简化客户端使用;
适配器 + 策略模式:适配器适配不同接口的策略,策略模式动态切换算法。
实战注意事项 :
装饰者模式:控制装饰层级、使用智能指针管理内存、明确装饰顺序;
适配器模式:避免过度适配、只负责接口转换不添加业务逻辑、优先使用对象适配器;
通用原则:优先组合而非继承、符合开放 - 封闭原则、接口简洁化、避免过度设计。
通过本章学习,你应能熟练运用装饰者模式和适配器模式解决实际开发中的'功能扩展'和'接口兼容'问题,结合两种模式的组合使用,编写灵活、可扩展、低耦合的 C++ 代码。后续章节将继续讲解其他结构型设计模式(如代理模式、组合模式),进一步完善你的设计模式知识体系。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online