注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。
动态扩展对象功能的利器
1. 模式定义与用途
核心思想
- 装饰器模式:通过组合对象而非继承,动态地给对象添加额外职责。
- 关键用途:
1.运行时扩展功能:无需修改原有类,支持按需叠加功能(如加密、压缩)。
2.替代多层继承:避免因功能组合导致的子类爆炸问题。
经典场景
- 数据流处理:为网络传输动态添加加密、压缩、缓存等能力。
- 日志系统:为日志消息添加时间戳、来源IP等元信息。
2. 模式结构解析
UML类图
+---------------------+ +---------------------+
| Component | | Decorator |
+---------------------+ +---------------------+
| + operation(): void |<|---------| - component: Component
+---------------------+ | + operation(): void | ^ +---------------------+ | ^ | +-------+------------+ | | |
+---------------------+ +--------------------+ +-------------------+
| ConcreteComponent | | ConcreteDecoratorA | | ConcreteDecoratorB |
+---------------------+ +--------------------+ +--------------------+
| + operation() | | + operation() | | + operation() |
+---------------------+ +--------------------+ +--------------------+
角色说明
Component
:抽象接口,定义核心功能方法(如send()
)。ConcreteComponent
:具体组件,实现基础功能(如明文数据发送)。Decorator
:装饰器基类,持有组件对象并转发请求。-
ConcreteDecorator
:具体装饰器,添加扩展功能(如加密)。
3. 现代C++实现示例
场景:网络数据流动态装饰
步骤1:定义抽象数据流接口
class DataStream {
public: virtual ~DataStream() = default; virtual void send(const std::string& data) = 0;
};
步骤2:实现基础数据流(明文传输)
class PlainStream : public DataStream {
public: void send(const std::string& data) override { std::cout << "发送明文: " << data << "\n"; }
};
步骤3:定义装饰器基类
class StreamDecorator : public DataStream {
public: StreamDecorator(std::unique_ptr<DataStream> stream) : stream_(std::move(stream)) {} void send(const std::string& data) override { stream_->send(data); // 默认转发请求 } protected: std::unique_ptr<DataStream> stream_;
};
步骤4:实现具体装饰器(加密与压缩)
// 加密装饰器
class EncryptedStream : public StreamDecorator {
public: using StreamDecorator::StreamDecorator; void send(const std::string& data) override { auto encrypted = "加密[" + data + "]"; stream_->send(encrypted); }
}; // 压缩装饰器
class CompressedStream : public StreamDecorator {
public: using StreamDecorator::StreamDecorator; void send(const std::string& data) override { auto compressed = "压缩[" + data + "]"; stream_->send(compressed); }
};
步骤5:客户端动态组合装饰器
int main() { // 基础数据流 auto plain = std::make_unique<PlainStream>(); // 动态添加装饰功能 auto encrypted = std::make_unique<EncryptedStream>(std::move(plain)); auto compressedAndEncrypted = std::make_unique<CompressedStream>(std::move(encrypted)); compressedAndEncrypted->send("Hello World"); // 输出: // 发送明文: 压缩[加密[Hello World]]
}
4. 应用场景示例
场景1:日志消息装饰
class Logger {
public: virtual ~Logger() = default; virtual void log(const std::string& msg) = 0;
}; // 基础日志
class FileLogger : public Logger { void log(const std::string& msg) override { /* 写入文件 */ }
}; // 时间戳装饰器
class TimestampLogger : public Logger {
public: TimestampLogger(std::unique_ptr<Logger> logger) : logger_(std::move(logger)) {} void log(const std::string& msg) override { auto timestamp = "[2023-10-01 12:00:00] "; logger_->log(timestamp + msg); } private: std::unique_ptr<Logger> logger_;
};
场景2:图形界面控件装饰
class Button {
public: virtual void render() = 0;
}; // 基础按钮
class BasicButton : public Button { void render() override { /* 绘制按钮 */ }
}; // 边框装饰器
class BorderDecorator : public Button {
public: BorderDecorator(std::unique_ptr<Button> button) : button_(std::move(button)) {} void render() override { button_->render(); std::cout << "添加红色边框\n"; } private: std::unique_ptr<Button> button_;
};
5. 优缺点分析
优点 | 缺点 |
---|---|
动态扩展对象功能,无需修改源码 | 装饰器嵌套过多会降低可读性 |
避免继承层次过深 | 装饰顺序可能影响结果(如先加密后压缩) |
支持运行时灵活组合功能 | 对象标识改变,typeid检测可能失效 |
6. 调试与优化策略
调试技巧(VS2022)
1. 跟踪装饰链调用:
- 在每个装饰器的send()方法内设置断点,观察数据流处理顺序。
2. 验证装饰器组合:
- 使用
dynamic_cast
检查装饰器类型(需启用RTTI)。
性能优化
1. 减少内存分配:
- 复用装饰器对象(如线程安全的对象池)。
2.批量处理优化:
class BufferedStream : public StreamDecorator {
public: void send(const std::string& data) override { buffer_.push_back(data); if (buffer_.size() >= 1024) { flush(); } }
private: std::vector<std::string> buffer_; void flush() { stream_->send(concat(buffer_)); buffer_.clear(); }
};