1. 装饰器模式在C++中的实现与应用
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向现有对象动态添加新功能而不改变其结构。这种模式通过创建包装对象来实现功能的扩展,是继承关系的一个灵活替代方案。
在C++中,装饰器模式特别适合以下场景:
- 需要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
- 当不能采用生成子类的方法进行扩展时(比如final类或需要大量子类的情况)
- 需要随时添加或撤销对象的功能
提示:装饰器模式与继承的关键区别在于,装饰器是在运行时动态添加功能,而继承是在编译时静态确定的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 装饰器模式的核心结构与实现
2.1 基本组件构成
一个典型的C++装饰器模式包含以下核心组件:
-
Component(抽象组件):
- 定义对象的接口,可以动态添加职责
- 通常是一个抽象基类或接口
cpp复制class Component { public: virtual ~Component() = default; virtual void operation() = 0; }; -
ConcreteComponent(具体组件):
- 定义实际要装饰的对象
cpp复制class ConcreteComponent : public Component { public: void operation() override { std::cout << "Basic functionality\n"; } }; -
Decorator(装饰器基类):
- 维护一个指向Component对象的指针并定义与Component一致的接口
cpp复制class Decorator : public Component { protected: Component* component; public: Decorator(Component* c) : component(c) {} void operation() override { if (component) component->operation(); } }; -
ConcreteDecorator(具体装饰器):
- 向组件添加具体职责
cpp复制class ConcreteDecoratorA : public Decorator { public: ConcreteDecoratorA(Component* c) : Decorator(c) {} void operation() override { Decorator::operation(); addedBehavior(); } void addedBehavior() { std::cout << "Added behavior A\n"; } };
2.2 完整示例实现
下面是一个完整的装饰器模式示例,展示如何通过多层装饰来扩展对象功能:
cpp复制#include <iostream>
#include <memory>
// 抽象组件
class Beverage {
public:
virtual ~Beverage() = default;
virtual std::string getDescription() const = 0;
virtual double cost() const = 0;
};
// 具体组件
class Espresso : public Beverage {
public:
std::string getDescription() const override {
return "Espresso";
}
double cost() const override {
return 1.99;
}
};
// 装饰器基类
class CondimentDecorator : public Beverage {
protected:
std::unique_ptr<Beverage> beverage;
public:
explicit CondimentDecorator(std::unique_ptr<Beverage> b)
: beverage(std::move(b)) {}
};
// 具体装饰器 - 牛奶
class Milk : public CondimentDecorator {
public:
explicit Milk(std::unique_ptr<Beverage> b)
: CondimentDecorator(std::move(b)) {}
std::string getDescription() const override {
return beverage->getDescription() + ", Milk";
}
double cost() const override {
return beverage->cost() + 0.20;
}
};
// 具体装饰器 - 摩卡
class Mocha : public CondimentDecorator {
public:
explicit Mocha(std::unique_ptr<Beverage> b)
: CondimentDecorator(std::move(b)) {}
std::string getDescription() const override {
return beverage->getDescription() + ", Mocha";
}
double cost() const override {
return beverage->cost() + 0.30;
}
};
// 使用示例
int main() {
auto beverage = std::make_unique<Espresso>();
std::cout << beverage->getDescription() << " $" << beverage->cost() << "\n";
auto beverage2 = std::make_unique<Milk>(std::make_unique<Mocha>(std::make_unique<Espresso>()));
std::cout << beverage2->getDescription() << " $" << beverage2->cost() << "\n";
return 0;
}
输出结果:
code复制Espresso $1.99
Espresso, Mocha, Milk $2.49
3. 装饰器模式的高级应用技巧
3.1 多重装饰与执行顺序
装饰器可以多层嵌套,形成装饰链。执行顺序是从最外层装饰器开始,向内逐层执行:
cpp复制auto beverage = std::make_unique<Mocha>(
std::make_unique<Milk>(
std::make_unique<Mocha>(
std::make_unique<Espresso>()
)
)
);
// 描述输出:Espresso, Mocha, Milk, Mocha
// 成本计算:1.99 + 0.30 + 0.20 + 0.30 = 2.79
注意:装饰器的执行顺序会影响最终结果。在设计时要明确装饰器的叠加顺序规则。
3.2 使用智能指针管理资源
现代C++推荐使用智能指针来管理装饰器链中的对象生命周期:
-
unique_ptr:适用于所有权单一的场景
cpp复制std::unique_ptr<Beverage> beverage = std::make_unique<Espresso>(); beverage = std::make_unique<Milk>(std::move(beverage)); -
shared_ptr:适用于需要共享所有权的场景
cpp复制auto beverage = std::make_shared<Espresso>(); auto decorated = std::make_shared<Milk>(beverage);
3.3 装饰器与模板的结合
可以将装饰器模式与模板结合,创建类型安全的装饰器:
cpp复制template <typename T>
class LoggingDecorator : public T {
static_assert(std::is_base_of<Component, T>::value,
"T must inherit from Component");
public:
void operation() override {
std::cout << "Before operation\n";
T::operation();
std::cout << "After operation\n";
}
};
// 使用
LoggingDecorator<ConcreteComponent> decorated;
decorated.operation();
4. 装饰器模式的典型应用场景
4.1 GUI组件装饰
在图形界面开发中,装饰器模式常用于为UI组件添加边框、滚动条等功能:
cpp复制class VisualComponent {
public:
virtual ~VisualComponent() = default;
virtual void draw() = 0;
};
class TextView : public VisualComponent {
public:
void draw() override {
// 绘制文本视图
}
};
class Decorator : public VisualComponent {
protected:
std::unique_ptr<VisualComponent> component;
public:
explicit Decorator(std::unique_ptr<VisualComponent> c)
: component(std::move(c)) {}
void draw() override {
if (component) component->draw();
}
};
class BorderDecorator : public Decorator {
int width;
public:
BorderDecorator(std::unique_ptr<VisualComponent> c, int w)
: Decorator(std::move(c)), width(w) {}
void draw() override {
Decorator::draw();
drawBorder(width);
}
void drawBorder(int w) {
// 绘制边框
}
};
4.2 I/O流装饰
C++标准库中的流装饰器(如std::istream_iterator)就是装饰器模式的典型应用:
cpp复制#include <fstream>
#include <iostream>
#include <algorithm>
#include <iterator>
void processStream(std::istream& is) {
std::copy(std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, " "));
}
int main() {
std::ifstream file("data.txt");
std::istringstream iss("This is a test");
// 装饰文件流
processStream(file);
// 装饰字符串流
processStream(iss);
return 0;
}
4.3 游戏开发中的属性加成
在游戏开发中,装饰器模式可用于实现装备、技能等对角色属性的动态加成:
cpp复制class Character {
public:
virtual ~Character() = default;
virtual int getAttack() const = 0;
virtual int getDefense() const = 0;
};
class Warrior : public Character {
public:
int getAttack() const override { return 10; }
int getDefense() const override { return 5; }
};
class Equipment : public Character {
protected:
std::unique_ptr<Character> character;
public:
explicit Equipment(std::unique_ptr<Character> c)
: character(std::move(c)) {}
};
class Sword : public Equipment {
public:
explicit Sword(std::unique_ptr<Character> c)
: Equipment(std::move(c)) {}
int getAttack() const override {
return character->getAttack() + 5;
}
int getDefense() const override {
return character->getDefense();
}
};
class Shield : public Equipment {
public:
explicit Shield(std::unique_ptr<Character> c)
: Equipment(std::move(c)) {}
int getAttack() const override {
return character->getAttack();
}
int getDefense() const override {
return character->getDefense() + 3;
}
};
// 创建装备了剑和盾的战士
auto hero = std::make_unique<Shield>(
std::make_unique<Sword>(
std::make_unique<Warrior>()
)
);
std::cout << "Attack: " << hero->getAttack()
<< ", Defense: " << hero->getDefense();
// 输出:Attack: 15, Defense: 8
5. 装饰器模式的优缺点与替代方案
5.1 主要优点
- 比继承更灵活:可以在运行时动态添加或移除功能
- 避免特征爆炸:不需要为每个功能组合创建子类
- 单一职责原则:将功能分解为多个小类,每个类只关注一个功能
- 开闭原则:无需修改现有代码即可扩展新功能
5.2 潜在缺点
- 小对象数量多:会产生大量小装饰器类,增加系统复杂度
- 装饰顺序敏感:多层装饰时,顺序会影响最终结果
- 移除装饰困难:一旦装饰,难以从对象中移除特定装饰层
- 初始化复杂:创建高度装饰的对象需要大量嵌套代码
5.3 替代方案比较
| 方案 | 适用场景 | 与装饰器对比 |
|---|---|---|
| 继承 | 编译时确定的静态扩展 | 装饰器更灵活,运行时动态变化 |
| 组合 | 对象包含其他对象实现功能 | 装饰器是透明包装,保持接口一致 |
| 策略模式 | 改变对象的算法或行为 | 装饰器是添加功能,策略是替换行为 |
| 责任链模式 | 多个处理器处理请求 | 装饰器是叠加功能,责任链是传递请求 |
6. 实际开发中的经验与陷阱
6.1 内存管理注意事项
-
所有权问题:明确装饰器是否应该拥有被装饰对象的所有权
- 使用
unique_ptr表示独占所有权 - 使用
shared_ptr表示共享所有权 - 原始指针仅用于观察,不管理生命周期
- 使用
-
循环引用风险:当装饰器和组件相互引用时可能导致内存泄漏
cpp复制// 错误示例:循环引用 class BadDecorator : public Component { Component* component; public: BadDecorator(Component* c) : component(c) { // 如果component也持有了BadDecorator的引用... } };
6.2 性能考量
-
多层装饰的开销:每层装饰都会增加一次间接调用
- 对于性能敏感的场景,考虑限制装饰层数
- 可以使用空对象模式优化无操作的装饰层
-
虚函数调用成本:装饰器模式通常依赖虚函数分派
- 在热点路径上,考虑使用CRTP模式减少虚函数调用
cpp复制template <typename Derived> class DecoratorBase : public Component { public: void operation() override { static_cast<Derived*>(this)->doOperation(); } };
6.3 设计陷阱与解决方案
-
过度装饰问题:
- 症状:装饰层数过多导致系统难以理解和维护
- 解决方案:设置装饰层数上限,或使用组合模式替代
-
接口膨胀问题:
- 症状:基础组件接口过于庞大,装饰器需要实现太多无关方法
- 解决方案:将大接口拆分为多个小接口,使用接口隔离原则
-
装饰顺序依赖:
- 症状:不同装饰顺序导致不同行为
- 解决方案:明确文档说明,或提供装饰器管理器控制顺序
7. C++17/20中的现代实现技术
7.1 使用std::variant实现类型安全装饰
C++17引入的std::variant可以创建类型安全的装饰器组合:
cpp复制#include <variant>
#include <vector>
using Decorator = std::variant<
std::monostate, // 无装饰
struct Border,
struct Shadow,
struct Color
>;
class ModernComponent {
std::vector<Decorator> decorators;
public:
void addDecorator(Decorator d) {
decorators.push_back(d);
}
void render() {
for (auto& d : decorators) {
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<T, std::monostate>) {
// 应用装饰效果
}
}, d);
}
}
};
7.2 使用概念约束装饰器类型
C++20的概念可以更好地约束装饰器类型:
cpp复制template <typename T>
concept Component = requires(T t) {
{ t.operation() } -> std::same_as<void>;
};
template <Component T>
class ModernDecorator : public T {
public:
void operation() override {
T::operation();
// 添加新功能
}
};
7.3 使用RAII管理装饰资源
利用RAII确保装饰资源的正确释放:
cpp复制class ScopedDecorator {
std::unique_ptr<Component> component;
public:
explicit ScopedDecorator(std::unique_ptr<Component> c)
: component(std::move(c)) {}
~ScopedDecorator() {
// 清理装饰添加的资源
}
void operation() override {
if (component) component->operation();
}
};
8. 测试装饰器模式的策略
8.1 单元测试装饰器
-
测试单个装饰器:
cpp复制TEST(DecoratorTest, AddsBehavior) { auto component = std::make_unique<ConcreteComponent>(); auto decorated = std::make_unique<ConcreteDecoratorA>(std::move(component)); testing::internal::CaptureStdout(); decorated->operation(); std::string output = testing::internal::GetCapturedStdout(); EXPECT_TRUE(output.find("Added behavior") != std::string::npos); } -
测试装饰器组合:
cpp复制TEST(DecoratorTest, CombinedBehavior) { auto component = std::make_unique<ConcreteComponent>(); auto decorated = std::make_unique<ConcreteDecoratorB>( std::make_unique<ConcreteDecoratorA>(std::move(component))); // 验证组合效果 }
8.2 性能基准测试
使用Google Benchmark测试装饰器性能影响:
cpp复制static void BM_PlainComponent(benchmark::State& state) {
ConcreteComponent c;
for (auto _ : state) {
c.operation();
}
}
BENCHMARK(BM_PlainComponent);
static void BM_DecoratedComponent(benchmark::State& state) {
auto c = std::make_unique<ConcreteDecoratorA>(
std::make_unique<ConcreteComponent>());
for (auto _ : state) {
c->operation();
}
}
BENCHMARK(BM_DecoratedComponent);
8.3 模拟测试
使用gmock模拟组件测试装饰器:
cpp复制class MockComponent : public Component {
public:
MOCK_METHOD(void, operation, (), (override));
};
TEST(DecoratorTest, CallsWrappedComponent) {
auto mock = std::make_unique<MockComponent>();
EXPECT_CALL(*mock, operation()).Times(1);
auto decorator = std::make_unique<ConcreteDecoratorA>(std::move(mock));
decorator->operation();
}
9. 与其他模式的协同使用
9.1 装饰器与工厂模式结合
创建装饰器工厂来简化复杂装饰链的构建:
cpp复制class DecoratorFactory {
public:
enum DecoratorType { SIMPLE, COMPLEX, ENHANCED };
static std::unique_ptr<Component> create(
DecoratorType type,
std::unique_ptr<Component> base)
{
switch (type) {
case SIMPLE: return std::make_unique<SimpleDecorator>(std::move(base));
case COMPLEX: return std::make_unique<ComplexDecorator>(std::move(base));
case ENHANCED: return std::make_unique<EnhancedDecorator>(std::move(base));
default: return base;
}
}
};
9.2 装饰器与观察者模式结合
使装饰器可观察状态变化:
cpp复制class ObservableDecorator : public Component, public Observable {
std::unique_ptr<Component> component;
public:
explicit ObservableDecorator(std::unique_ptr<Component> c)
: component(std::move(c)) {}
void operation() override {
notifyObservers("Before operation");
component->operation();
notifyObservers("After operation");
}
};
9.3 装饰器与访问者模式结合
使用访问者模式遍历装饰器结构:
cpp复制class DecoratorVisitor {
public:
virtual void visit(Component*) = 0;
virtual void visit(Decorator*) = 0;
};
class PrintVisitor : public DecoratorVisitor {
void visit(Component* c) override {
std::cout << "Visiting component\n";
}
void visit(Decorator* d) override {
std::cout << "Visiting decorator\n";
}
};
class VisitableDecorator : public Decorator {
public:
using Decorator::Decorator;
void accept(DecoratorVisitor& v) {
v.visit(this);
if (component) {
if (auto vd = dynamic_cast<VisitableDecorator*>(component.get())) {
vd->accept(v);
} else {
v.visit(component.get());
}
}
}
};
10. 实际项目中的应用案例
10.1 日志系统装饰器
为日志系统添加装饰功能,如时间戳、日志级别等:
cpp复制class Logger {
public:
virtual ~Logger() = default;
virtual void log(const std::string& message) = 0;
};
class FileLogger : public Logger {
std::ofstream logFile;
public:
explicit FileLogger(const std::string& filename)
: logFile(filename) {}
void log(const std::string& message) override {
logFile << message << "\n";
}
};
class LoggerDecorator : public Logger {
protected:
std::unique_ptr<Logger> logger;
public:
explicit LoggerDecorator(std::unique_ptr<Logger> l)
: logger(std::move(l)) {}
void log(const std::string& message) override {
if (logger) logger->log(message);
}
};
class TimestampLogger : public LoggerDecorator {
public:
using LoggerDecorator::LoggerDecorator;
void log(const std::string& message) override {
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
LoggerDecorator::log(std::ctime(&time) + (" " + message));
}
};
// 使用
auto logger = std::make_unique<TimestampLogger>(
std::make_unique<FileLogger>("app.log"));
logger->log("System started");
10.2 网络请求处理装饰器
为网络请求添加装饰功能,如重试、缓存、日志等:
cpp复制class HttpRequest {
public:
virtual ~HttpRequest() = default;
virtual std::string execute(const std::string& url) = 0;
};
class BasicHttpRequest : public HttpRequest {
public:
std::string execute(const std::string& url) override {
// 实际网络请求实现
return "Response from " + url;
}
};
class RetryDecorator : public HttpRequest {
std::unique_ptr<HttpRequest> request;
int maxRetries;
public:
RetryDecorator(std::unique_ptr<HttpRequest> r, int retries)
: request(std::move(r)), maxRetries(retries) {}
std::string execute(const std::string& url) override {
for (int i = 0; i <= maxRetries; ++i) {
try {
return request->execute(url);
} catch (const std::exception& e) {
if (i == maxRetries) throw;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
throw std::runtime_error("Max retries exceeded");
}
};
// 创建带重试功能的HTTP客户端
auto client = std::make_unique<RetryDecorator>(
std::make_unique<BasicHttpRequest>(), 3);
auto response = client->execute("https://example.com");
10.3 数据流处理管道
构建数据处理管道,每个处理步骤都是一个装饰器:
cpp复制class DataProcessor {
public:
virtual ~DataProcessor() = default;
virtual std::vector<int> process(const std::vector<int>& data) = 0;
};
class FilterProcessor : public DataProcessor {
std::unique_ptr<DataProcessor> next;
public:
explicit FilterProcessor(std::unique_ptr<DataProcessor> n = nullptr)
: next(std::move(n)) {}
std::vector<int> process(const std::vector<int>& data) override {
auto result = data;
// 过滤偶数
result.erase(std::remove_if(result.begin(), result.end(),
[](int x) { return x % 2 == 0; }), result.end());
if (next) return next->process(result);
return result;
}
};
class SortProcessor : public DataProcessor {
std::unique_ptr<DataProcessor> next;
public:
explicit SortProcessor(std::unique_ptr<DataProcessor> n = nullptr)
: next(std::move(n)) {}
std::vector<int> process(const std::vector<int>& data) override {
auto result = data;
std::sort(result.begin(), result.end());
if (next) return next->process(result);
return result;
}
};
// 构建处理管道:先过滤后排序
auto processor = std::make_unique<SortProcessor>(
std::make_unique<FilterProcessor>());
auto result = processor->process({3,1,4,1,5,9,2,6});
// 结果: {1, 1, 3, 5, 9}
