1. 装饰器模式的核心概念与应用场景
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变现有对象结构的情况下,动态地扩展其功能。这种模式通过创建包装对象来实现功能的扩展,而不是通过继承。
在C++中,装饰器模式特别适合以下场景:
- 当需要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
- 当不能采用继承来扩展功能时(例如final类)
- 当需要随时添加或撤销对象的功能时
装饰器模式与继承的关键区别在于:
- 继承是静态的,在编译时确定
- 装饰是动态的,可以在运行时组合
提示:装饰器模式在C++标准库的IO流设计中广泛应用,比如std::istream和std::ostream的装饰器(如std::ifstream、std::ofstream)。
2. 装饰器模式的经典实现结构
2.1 基本组件角色
一个标准的装饰器模式实现包含以下核心组件:
- Component(抽象组件)
- 定义对象的接口,可以是一个抽象类或接口
- 声明了被装饰对象和装饰器的公共操作
cpp复制class Component {
public:
virtual ~Component() = default;
virtual void operation() const = 0;
};
- ConcreteComponent(具体组件)
- 实现Component接口的具体类
- 定义将被装饰器扩展的基本对象
cpp复制class ConcreteComponent : public Component {
public:
void operation() const override {
std::cout << "Basic functionality\n";
}
};
- Decorator(抽象装饰器)
- 继承自Component,持有一个Component指针
- 定义装饰器的公共接口
cpp复制class Decorator : public Component {
protected:
Component* component_;
public:
Decorator(Component* component) : component_(component) {}
void operation() const override {
if (component_) {
component_->operation();
}
}
};
- ConcreteDecorator(具体装饰器)
- 实现具体的装饰逻辑
- 可以在调用被装饰对象前后添加额外行为
cpp复制class ConcreteDecoratorA : public Decorator {
public:
ConcreteDecoratorA(Component* component) : Decorator(component) {}
void operation() const override {
std::cout << "Decorator A pre-processing\n";
Decorator::operation();
std::cout << "Decorator A post-processing\n";
}
};
2.2 装饰器的链式调用
装饰器最强大的特性是支持链式调用,即一个装饰器可以装饰另一个装饰器:
cpp复制Component* component = new ConcreteComponent();
component = new ConcreteDecoratorA(component); // 第一次装饰
component = new ConcreteDecoratorB(component); // 第二次装饰
component->operation();
这种链式调用会形成类似"洋葱"的结构,调用从最外层装饰器开始,层层向内传递,然后再从内向外返回。
3. 实战案例:游戏角色装备系统
让我们通过一个游戏开发中的实际案例来展示装饰器模式的应用。假设我们正在开发一个RPG游戏,需要为角色设计装备系统。
3.1 基础角色类设计
首先定义基础角色接口和实现:
cpp复制// 角色接口
class Character {
public:
virtual ~Character() = default;
virtual void displayStats() const = 0;
virtual int getAttack() const = 0;
virtual int getDefense() const = 0;
};
// 基础角色实现
class BasicCharacter : public Character {
std::string name_;
int attack_;
int defense_;
public:
BasicCharacter(std::string name, int attack, int defense)
: name_(std::move(name)), attack_(attack), defense_(defense) {}
void displayStats() const override {
std::cout << name_ << " stats:\n"
<< "Attack: " << attack_ << "\n"
<< "Defense: " << defense_ << "\n";
}
int getAttack() const override { return attack_; }
int getDefense() const override { return defense_; }
};
3.2 装备装饰器实现
接下来实现装备装饰器基类和具体装备:
cpp复制// 装备装饰器基类
class EquipmentDecorator : public Character {
protected:
Character* character_;
public:
EquipmentDecorator(Character* character) : character_(character) {}
void displayStats() const override {
character_->displayStats();
}
int getAttack() const override {
return character_->getAttack();
}
int getDefense() const override {
return character_->getDefense();
}
};
// 具体装备:剑
class Sword : public EquipmentDecorator {
int attackBonus_;
public:
Sword(Character* character, int bonus)
: EquipmentDecorator(character), attackBonus_(bonus) {}
void displayStats() const override {
EquipmentDecorator::displayStats();
std::cout << "Equipped with Sword (+" << attackBonus_ << " attack)\n";
}
int getAttack() const override {
return EquipmentDecorator::getAttack() + attackBonus_;
}
};
// 具体装备:盾牌
class Shield : public EquipmentDecorator {
int defenseBonus_;
public:
Shield(Character* character, int bonus)
: EquipmentDecorator(character), defenseBonus_(bonus) {}
void displayStats() const override {
EquipmentDecorator::displayStats();
std::cout << "Equipped with Shield (+" << defenseBonus_ << " defense)\n";
}
int getDefense() const override {
return EquipmentDecorator::getDefense() + defenseBonus_;
}
};
3.3 使用示例
cpp复制int main() {
// 创建基础角色
Character* hero = new BasicCharacter("Hero", 10, 5);
hero->displayStats();
// 装备剑
hero = new Sword(hero, 5);
hero->displayStats();
// 再装备盾牌
hero = new Shield(hero, 3);
hero->displayStats();
// 查看最终属性
std::cout << "Final Attack: " << hero->getAttack() << "\n";
std::cout << "Final Defense: " << hero->getDefense() << "\n";
delete hero;
return 0;
}
输出结果:
code复制Hero stats:
Attack: 10
Defense: 5
Hero stats:
Attack: 10
Defense: 5
Equipped with Sword (+5 attack)
Hero stats:
Attack: 10
Defense: 5
Equipped with Sword (+5 attack)
Equipped with Shield (+3 defense)
Final Attack: 15
Final Defense: 8
4. 装饰器模式的高级应用技巧
4.1 装饰器的移除与替换
在实际应用中,我们可能需要动态移除或替换装饰器。这需要稍微修改我们的设计:
cpp复制class RemovableDecorator : public Decorator {
public:
RemovableDecorator(Component* component) : Decorator(component) {}
// 返回被装饰的原始组件,以便可以移除当前装饰器
Component* removeDecorator() {
Component* inner = component_;
component_ = nullptr; // 防止删除时递归删除
return inner;
}
};
使用示例:
cpp复制Component* component = new ConcreteComponent();
component = new ConcreteDecoratorA(component); // 添加装饰器A
// 需要移除装饰器A时
if (auto* removable = dynamic_cast<RemovableDecorator*>(component)) {
Component* inner = removable->removeDecorator();
delete removable; // 删除装饰器A
component = inner; // 恢复原始组件
}
4.2 装饰器与智能指针
在现代C++中,使用原始指针管理资源容易导致内存泄漏。我们可以用智能指针改进:
cpp复制class Component {
public:
virtual ~Component() = default;
virtual void operation() const = 0;
};
using ComponentPtr = std::shared_ptr<Component>;
class Decorator : public Component {
protected:
ComponentPtr component_;
public:
Decorator(ComponentPtr component) : component_(std::move(component)) {}
void operation() const override {
if (component_) {
component_->operation();
}
}
};
// 使用示例
ComponentPtr component = std::make_shared<ConcreteComponent>();
component = std::make_shared<ConcreteDecoratorA>(component);
component->operation();
4.3 装饰器与模板元编程
对于性能敏感的场合,可以使用模板实现编译时装饰器:
cpp复制template <typename T>
class LoggingDecorator : public T {
public:
void operation() const override {
std::cout << "Before operation\n";
T::operation();
std::cout << "After operation\n";
}
};
// 使用示例
using DecoratedComponent = LoggingDecorator<ConcreteComponent>;
DecoratedComponent component;
component.operation();
这种方式的优点是零运行时开销,但缺点是灵活性较低,装饰行为在编译时就固定了。
5. 装饰器模式的优缺点与替代方案
5.1 优点
- 比继承更灵活:可以在运行时动态添加或移除功能
- 避免类爆炸:不需要为每种功能组合创建子类
- 单一职责原则:将功能划分为多个小类,每个类只关注一个功能
- 开闭原则:无需修改现有代码即可扩展功能
5.2 缺点
- 小对象数量多:会产生许多小装饰器对象,可能增加系统复杂度
- 装饰顺序影响结果:装饰器的应用顺序会影响最终行为
- 移除装饰器较复杂:需要额外机制来移除特定装饰器
5.3 替代方案
- 策略模式:如果主要目标是改变对象的行为,而不仅仅是扩展功能
- 适配器模式:如果需要改变对象的接口
- 组合模式:如果需要以树形结构组织对象
提示:在实际项目中,装饰器模式常与工厂模式结合使用,通过工厂来创建和管理装饰器链。
6. 装饰器模式在C++标准库中的应用
装饰器模式在C++标准库中有多处应用,最典型的是IO流系统:
6.1 IO流装饰器
C++的标准IO流本身就是装饰器模式的经典实现:
cpp复制#include <fstream>
#include <iostream>
#include <iomanip>
int main() {
// 基础输出流
std::ostream& cout = std::cout;
// 装饰器:设置输出宽度
cout << std::setw(10) << "Hello";
// 文件流是iostream的装饰器
std::ofstream file("output.txt");
file << "Writing to file\n";
// 多个装饰器组合
std::ostringstream oss;
oss << std::hex << std::uppercase << 255;
std::cout << oss.str(); // 输出FF
}
6.2 正则表达式装饰器
C++11引入的正则表达式库也使用了装饰器思想:
cpp复制#include <regex>
std::regex basic_re("abc");
std::regex icase_re("abc", std::regex_constants::icase); // 装饰器:忽略大小写
7. 性能考量与优化
虽然装饰器模式提供了灵活性,但在性能敏感的场景需要考虑以下因素:
7.1 虚函数调用开销
装饰器模式通常涉及大量虚函数调用,可能影响性能。解决方法:
- 对性能关键路径考虑使用CRTP模式减少虚函数调用
- 使用final关键字修饰不需要进一步重载的方法
cpp复制class ConcreteDecorator final : public Decorator {
public:
// final阻止进一步装饰
void operation() const final override {
// ...
}
};
7.2 内存碎片化
频繁创建/销毁小装饰器对象可能导致内存碎片。解决方法:
- 使用对象池预分配装饰器
- 考虑使用flyweight模式共享装饰器状态
7.3 编译时装饰器
对于已知的装饰组合,可以使用模板实现编译时装饰:
cpp复制template <typename Component>
class TimingDecorator : public Component {
public:
void operation() const {
auto start = std::chrono::high_resolution_clock::now();
Component::operation();
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Operation took "
<< std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()
<< "μs\n";
}
};
// 使用
using Decorated = TimingDecorator<ConcreteComponent>;
Decorated d;
d.operation();
8. 测试装饰器代码的注意事项
测试装饰器代码时需要考虑以下特殊因素:
8.1 测试单个装饰器
确保每个装饰器在隔离环境下正常工作:
cpp复制TEST(DecoratorATest, AddsPrefixAndSuffix) {
MockComponent mock;
EXPECT_CALL(mock, operation()).WillOnce(Return("test"));
ConcreteDecoratorA decorator(&mock);
EXPECT_EQ(decorator.operation(), "DecoratorA(test)");
}
8.2 测试装饰器组合
验证装饰器组合时的调用顺序和结果:
cpp复制TEST(DecoratorCombinationTest, OrderMatters) {
ConcreteComponent component;
ConcreteDecoratorA decoratorA(&component);
ConcreteDecoratorB decoratorB(&decoratorA);
EXPECT_EQ(decoratorB.operation(), "DecoratorB(DecoratorA(ConcreteComponent))");
}
8.3 性能测试
对装饰器链进行性能基准测试:
cpp复制BENCHMARK(DecoratorChainPerformance) {
Component* component = new ConcreteComponent();
for (int i = 0; i < 10; ++i) {
component = new ConcreteDecoratorA(component);
}
component->operation();
// 清理代码...
}
9. 实际项目中的经验分享
在实际C++项目中使用装饰器模式时,我总结了以下经验教训:
-
控制装饰深度:装饰器链不宜过长,通常3-4层足够,过深会影响可维护性
-
明确装饰顺序:文档化装饰器的应用顺序要求,特别是当装饰器有依赖关系时
-
统一装饰器接口:确保所有装饰器遵循相同的接口约定,避免意外行为
-
考虑异常安全:装饰器构造函数中分配资源时,要确保异常安全
cpp复制class SafeDecorator : public Decorator {
Resource* resource_;
public:
SafeDecorator(Component* component)
: Decorator(component), resource_(nullptr) {
resource_ = new Resource(); // 可能抛出异常
// 如果上面抛出异常,component不会被泄漏
// 因为基类构造函数已经完成
}
~SafeDecorator() {
delete resource_;
}
};
-
避免循环装饰:实现机制防止装饰器装饰自身或形成循环引用
-
考虑线程安全:如果装饰器会在多线程环境中使用,确保线程安全
cpp复制class ThreadSafeDecorator : public Decorator {
mutable std::mutex mtx_;
public:
ThreadSafeDecorator(Component* component) : Decorator(component) {}
void operation() const override {
std::lock_guard<std::mutex> lock(mtx_);
Decorator::operation();
}
};
10. 现代C++中的装饰器模式演进
随着C++语言的发展,装饰器模式也有一些新的实现方式:
10.1 使用std::function实现装饰器
cpp复制using Operation = std::function<void()>;
auto decorate(Operation op, std::string_view message) {
return [=] {
std::cout << "Before: " << message << "\n";
op();
std::cout << "After: " << message << "\n";
};
}
void basicOperation() {
std::cout << "Basic operation\n";
}
int main() {
auto op = decorate(basicOperation, "First decorator");
op = decorate(op, "Second decorator");
op();
}
10.2 使用可变参数模板实现装饰器工厂
cpp复制template <typename Component, typename... Decorators>
auto makeDecoratedComponent(Component* component, Decorators... decorators) {
// 使用折叠表达式应用所有装饰器
((component = decorators(component)), ...);
return component;
}
// 使用示例
auto decorated = makeDecoratedComponent(
new ConcreteComponent(),
[](auto* c) { return new ConcreteDecoratorA(c); },
[](auto* c) { return new ConcreteDecoratorB(c); }
);
10.3 使用概念约束装饰器类型
C++20引入了概念,可以更好地约束装饰器类型:
cpp复制template <typename D>
concept Decorator = requires(D d, Component* c) {
{ d(c) } -> std::same_as<Component*>;
};
template <typename Component, Decorator... Decorators>
auto makeDecorated(Component* component, Decorators... decorators) {
((component = decorators(component)), ...);
return component;
}
11. 装饰器模式与其他模式的协作
装饰器模式常与其他设计模式配合使用,形成更强大的设计:
11.1 装饰器+工厂模式
通过工厂创建预配置的装饰器链:
cpp复制class DecoratorFactory {
public:
static Component* createDefaultDecoratedComponent() {
Component* component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
return component;
}
};
11.2 装饰器+组合模式
装饰器可以装饰组合对象:
cpp复制class Composite : public Component {
std::vector<Component*> children_;
public:
void add(Component* component) {
children_.push_back(component);
}
void operation() const override {
for (auto* child : children_) {
child->operation();
}
}
};
// 使用
Composite* composite = new Composite();
composite->add(new ConcreteComponent());
composite = new ConcreteDecoratorA(composite);
11.3 装饰器+策略模式
装饰器改变对象结构,策略改变算法:
cpp复制class StrategyDecorator : public Decorator {
std::unique_ptr<Strategy> strategy_;
public:
StrategyDecorator(Component* component, std::unique_ptr<Strategy> strategy)
: Decorator(component), strategy_(std::move(strategy)) {}
void operation() const override {
strategy_->preProcess();
Decorator::operation();
strategy_->postProcess();
}
};
12. 常见问题与解决方案
12.1 如何调试装饰器链?
调试装饰器链可能会比较困难,因为调用会在多个装饰器之间跳转。可以采用以下方法:
- 添加日志装饰器:
cpp复制class LoggingDecorator : public Decorator {
public:
LoggingDecorator(Component* component) : Decorator(component) {}
void operation() const override {
std::cout << "Entering LoggingDecorator\n";
Decorator::operation();
std::cout << "Exiting LoggingDecorator\n";
}
};
- 使用RTTI识别装饰器类型:
cpp复制void debugPrint(Component* component) {
if (auto* decorator = dynamic_cast<Decorator*>(component)) {
std::cout << "Decorator type: " << typeid(*decorator).name() << "\n";
debugPrint(decorator->getComponent()); // 递归调试内部组件
} else {
std::cout << "Base component type: " << typeid(*component).name() << "\n";
}
}
12.2 如何处理装饰器的资源所有权?
装饰器模式中资源所有权是一个常见问题。有几种解决方案:
- 明确所有权规则:
- 装饰器获得组件所有权
- 销毁装饰器时自动销毁组件
cpp复制class OwningDecorator : public Decorator {
public:
OwningDecorator(Component* component) : Decorator(component) {}
~OwningDecorator() {
delete component_;
}
};
- 使用共享所有权:
- 使用shared_ptr管理组件生命周期
cpp复制class SharedDecorator : public Component {
std::shared_ptr<Component> component_;
public:
SharedDecorator(std::shared_ptr<Component> component)
: component_(std::move(component)) {}
void operation() const override {
if (component_) {
component_->operation();
}
}
};
12.3 如何避免装饰器接口膨胀?
随着系统演进,基础组件接口可能会变得臃肿。解决方法:
- 接口分离:
- 将大接口拆分为多个小接口
- 装饰器只实现相关接口
cpp复制class Renderable {
public:
virtual void render() const = 0;
};
class Updatable {
public:
virtual void update(float dt) = 0;
};
class RenderDecorator : public Renderable {
Renderable* target_;
public:
RenderDecorator(Renderable* target) : target_(target) {}
void render() const override {
// 装饰逻辑
target_->render();
}
};
- 默认实现:
- 在装饰器基类中提供默认实现
- 具体装饰器只重写需要的方法
cpp复制class DefaultDecorator : public Component {
protected:
Component* component_;
public:
DefaultDecorator(Component* component) : component_(component) {}
// 默认转发所有方法
void operation1() const override { if (component_) component_->operation1(); }
void operation2() override { if (component_) component_->operation2(); }
// ...
};
13. 装饰器模式的变体与扩展
13.1 静态装饰器(编译时装饰)
使用模板实现编译时装饰:
cpp复制template <typename T>
class StaticDecorator : public T {
public:
// 转发所有构造函数
using T::T;
void operation() const override {
std::cout << "Decorator pre-processing\n";
T::operation();
std::cout << "Decorator post-processing\n";
}
};
// 使用
StaticDecorator<ConcreteComponent> decorated;
decorated.operation();
13.2 策略化装饰器
将装饰行为作为策略注入:
cpp复制class DecoratorStrategy {
public:
virtual ~DecoratorStrategy() = default;
virtual void before() const = 0;
virtual void after() const = 0;
};
class StrategyDecorator : public Decorator {
std::unique_ptr<DecoratorStrategy> strategy_;
public:
StrategyDecorator(Component* component, std::unique_ptr<DecoratorStrategy> strategy)
: Decorator(component), strategy_(std::move(strategy)) {}
void operation() const override {
strategy_->before();
Decorator::operation();
strategy_->after();
}
};
13.3 装饰器注册表
实现可插拔的装饰器系统:
cpp复制class DecoratorRegistry {
std::unordered_map<std::string, std::function<Component*(Component*)>> decorators_;
public:
void registerDecorator(std::string name, auto factory) {
decorators_[std::move(name)] = factory;
}
Component* applyDecorator(Component* component, std::string_view name) {
if (auto it = decorators_.find(name); it != decorators_.end()) {
return it->second(component);
}
return component;
}
};
// 使用
DecoratorRegistry registry;
registry.registerDecorator("log", [](Component* c) { return new LoggingDecorator(c); });
Component* component = new ConcreteComponent();
component = registry.applyDecorator(component, "log");
14. 性能敏感场景的优化实践
在游戏开发、高频交易等性能敏感领域,装饰器模式需要特别优化:
14.1 装饰器数据局部性优化
将装饰器数据紧凑存储,提高缓存利用率:
cpp复制class CompactDecorator : public Decorator {
// 将常用数据放在一起
struct {
int bonus1;
int bonus2;
float multiplier;
} data_;
public:
CompactDecorator(Component* component, int b1, int b2, float m)
: Decorator(component), data_{b1, b2, m} {}
void operation() const override {
// 使用data_中的装饰数据
Decorator::operation();
}
};
14.2 装饰器批处理
合并多个装饰操作为单次操作:
cpp复制class BatchDecorator : public Decorator {
std::vector<std::function<void()>> operations_;
public:
BatchDecorator(Component* component) : Decorator(component) {}
void addOperation(std::function<void()> op) {
operations_.push_back(std::move(op));
}
void operation() const override {
for (const auto& op : operations_) {
op();
}
Decorator::operation();
}
};
14.3 装饰器内存池
使用对象池管理装饰器实例:
cpp复制class DecoratorPool {
std::vector<std::unique_ptr<Decorator>> pool_;
public:
template <typename D, typename... Args>
D* create(Component* component, Args&&... args) {
if (pool_.empty()) {
pool_.reserve(10);
for (int i = 0; i < 10; ++i) {
pool_.push_back(std::make_unique<D>(nullptr, std::forward<Args>(args)...));
}
}
auto& decorator = pool_.back();
decorator->reset(component); // 假设Decorator有reset方法
D* result = static_cast<D*>(decorator.get());
pool_.pop_back();
return result;
}
void release(Decorator* decorator) {
pool_.push_back(std::unique_ptr<Decorator>(decorator));
}
};
15. 跨平台开发的注意事项
在不同平台上使用装饰器模式时,需要注意:
15.1 ABI兼容性
确保装饰器接口在不同编译器和平台间保持兼容:
cpp复制// 使用C链接和标准布局保证兼容性
extern "C" {
struct ComponentVTable {
void (*operation)(void*);
void (*destroy)(void*);
};
struct Component {
ComponentVTable* vtable;
};
struct Decorator {
Component base;
Component* wrapped;
};
}
15.2 线程局部装饰器
实现线程特定的装饰行为:
cpp复制class ThreadLocalDecorator : public Decorator {
static thread_local int threadSpecificData;
public:
ThreadLocalDecorator(Component* component) : Decorator(component) {}
void operation() const override {
// 使用线程局部数据
threadSpecificData++;
Decorator::operation();
}
};
thread_local int ThreadLocalDecorator::threadSpecificData = 0;
15.3 平台特定装饰器
为不同平台提供不同的装饰器实现:
cpp复制class PlatformDecorator : public Decorator {
public:
PlatformDecorator(Component* component) : Decorator(component) {}
void operation() const override {
#ifdef _WIN32
windowsSpecificOperation();
#elif defined(__linux__)
linuxSpecificOperation();
#endif
Decorator::operation();
}
};
16. 装饰器模式的反模式与误用
虽然装饰器模式很强大,但也有一些常见的误用情况:
16.1 装饰器滥用
过度使用装饰器会导致:
- 系统复杂度急剧上升
- 调试困难
- 性能下降
解决方案:限制装饰器层级,超过3层考虑重构
16.2 装饰器与继承混淆
错误地用装饰器替代本应使用继承的情况:
cpp复制// 错误:Person和Student是"is-a"关系,应该用继承
class StudentDecorator : public Decorator {
// 装饰Person对象使其成为Student
};
// 正确:Student继承Person
class Student : public Person {
// ...
};
判断准则:如果关系是"is-a"用继承,如果是"has-a"或"enhances-a"用装饰器
16.3 装饰器状态管理混乱
装饰器意外修改被装饰对象的状态:
cpp复制class BadDecorator : public Decorator {
public:
void operation() override {
// 错误:直接修改被装饰对象内部状态
component_->someInternalState = 42;
Decorator::operation();
}
};
最佳实践:装饰器应只通过公共接口与被装饰对象交互
17. C++20/23新特性对装饰器模式的影响
现代C++的新特性为装饰器模式带来了新的可能性:
17.1 使用概念约束装饰器
cpp复制template <typename T>
concept Component = requires(T t) {
{ t.operation() } -> std::same_as<void>;
};
template <Component C>
class ConceptDecorator : public C {
public:
void operation() const override {
std::cout << "Decorated operation\n";
C::operation();
}
};
17.2 使用协程实现异步装饰器
cpp复制class AsyncDecorator : public Decorator {
public:
std::future<void> asyncOperation() const {
co_await std::async(std::launch::async, [this] {
Decorator::operation();
});
}
};
17.3 使用反射简化装饰器注册
C++23可能引入的反射特性可以简化装饰器注册:
cpp复制// 假设的C++23代码
template <typename D>
void registerDecorator() {
constexpr auto refl = reflexpr(D);
std::string name = refl.get_name();
DecoratorRegistry::instance().register(name, [](Component* c) {
return new D(c);
});
}
18. 领域特定装饰器案例
18.1 网络通信中的装饰器
cpp复制class Socket {
public:
virtual ~Socket() = default;
virtual void send(const char* data, size_t size) = 0;
virtual void receive(char* buffer, size_t size) = 0;
};
class EncryptionDecorator : public Socket {
Socket* socket_;
CryptoContext crypto_;
public:
EncryptionDecorator(Socket* socket, CryptoKey key)
: socket_(socket), crypto_(key) {}
void send(const char* data, size_t size) override {
auto encrypted = crypto_.encrypt(data, size);
socket_->send(encrypted.data(), encrypted.size());
}
void receive(char* buffer, size_t size) override {
char temp[1024];
socket_->receive(temp, sizeof(temp));
auto decrypted = crypto_.decrypt(temp, strlen(temp));
std::copy(decrypted.begin(), decrypted.end(), buffer);
}
};
18.2 GUI系统中的装饰器
cpp复制class Widget {
public:
virtual ~Widget() = default;
virtual void draw() const = 0;
virtual Rect bounds() const = 0;
};
class BorderDecorator : public Widget {
Widget* widget_;
Color color_;
int width_;
public:
BorderDecorator(Widget* widget, Color c, int w)
: widget_(widget), color_(c), width_(w) {}
void draw() const override {
widget_->draw();
drawBorder(bounds(), color_, width_);
}
Rect bounds() const override {
auto b = widget_->bounds();
b.inflate(width_);
return b;
}
};
18.3 数据库访问层的装饰器
cpp复制class DatabaseConnection {
public:
virtual ~DatabaseConnection() = default;
virtual QueryResult execute(const std::string& query) = 0;
};
class LoggingConnection : public DatabaseConnection {
DatabaseConnection* connection_;
std::ostream& log_;
public:
LoggingConnection(DatabaseConnection* conn, std::ostream& log)
: connection_(conn), log_(log) {}
QueryResult execute(const std::string& query) override {
log_ << "Executing: " << query << "\n";
auto start = std::chrono::steady_clock::now();
auto result = connection_->execute(query);
auto end = std::chrono::steady_clock::now();
log_ << "Query took "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
return result;
}
};
19. 测试驱动开发(TDD)中的装饰器
采用TDD方式开发装饰器时,可以遵循以下步骤:
19.1 定义组件接口测试
cpp复制TEST(ComponentTest, BasicOperation) {
MockComponent component;
EXPECT_CALL(component, operation());
component.operation();
}
19.2 测试装饰器基本行为
cpp复制TEST(DecoratorTest, ForwardsCallsToWrappedComponent) {
MockComponent* mock = new MockComponent;
ConcreteDecorator decorator(mock);
EXPECT_CALL(*mock, operation());
decorator.operation();
delete mock; // 假设装饰器不接管所有权
}
19.3 测试装饰器新增功能
cpp复制TEST(DecoratorTest, AddsNewFunctionality) {
NiceMock<MockComponent> mock; // 不关心mock的调用
ConcreteDecorator decorator(&mock);
testing::internal::CaptureStdout();
decorator.operation();
std::string output = testing::internal::GetCapturedStdout();
EXPECT_TRUE(output.find("Decorator added behavior") != std::string::npos);
}
19.4 测试装饰器组合
cpp复制TEST(DecoratorCombinationTest, MultipleDecoratorsWorkTogether) {
ConcreteComponent component;
DecoratorA decoratorA(&component);
DecoratorB decoratorB(&decoratorA);
testing::internal::CaptureStdout();
decoratorB.operation();
std::string output = testing::internal::GetCapturedStdout();
// 验证装饰器B和A的行为都生效
EXPECT_TRUE(output.find("DecoratorA") != std::string::npos);
EXPECT_TRUE(output.find("DecoratorB") != std::string::npos);
}
20. 装饰器模式的未来发展趋势
随着软件开发的演进,装饰器模式也在不断发展:
20.1 函数式风格的装饰器
现代C++支持函数式编程风格,可以这样实现装饰器:
cpp复制auto log_call = [](auto f) {
return [f](auto&&... args) {
std::cout << "Calling function\n";
auto result = f(std::forward<decltype(args)>(args)...);
std::cout << "Function returned\n";
return result;
};
};
auto decorated_func = log_call([](int x) { return x * 2; });
std::cout << decorated_func(21); // 输出调用日志和42
20.2 编译时装饰器组合
使用C++模板元编程实现编译时装饰器组合:
cpp复制template <typename T, template<typename> class... Decorators>
struct Decorate {
using type = typename Decorate<typename Decorators<T>::type, Decorators...>::type;
};
template <typename T,
