注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。
动态扩展对象功能的利器
1. 模式定义与用途
核心思想
- 装饰器模式:通过组合对象而非继承,动态地给对象添加额外职责。
- 关键用途 :
1.运行时扩展功能:无需修改原有类,支持按需叠加功能(如加密、压缩)。
2.替代多层继承:避免因功能组合导致的子类爆炸问题。
经典场景
- 数据流处理:为网络传输动态添加加密、压缩、缓存等能力。
- 日志系统:为日志消息添加时间戳、来源IP等元信息。
2. 模式结构解析
UML类图
plaintext
+---------------------+ +---------------------+
| Component | | Decorator |
+---------------------+ +---------------------+
| + operation(): void |<|---------| - component: Component
+---------------------+ | + operation(): void |
^ +---------------------+
| ^
| +-------+------------+
| | |
+---------------------+ +--------------------+ +-------------------+
| ConcreteComponent | | ConcreteDecoratorA | | ConcreteDecoratorB |
+---------------------+ +--------------------+ +--------------------+
| + operation() | | + operation() | | + operation() |
+---------------------+ +--------------------+ +--------------------+
角色说明
Component
:抽象接口,定义核心功能方法(如send()
)。ConcreteComponent
:具体组件,实现基础功能(如明文数据发送)。Decorator
:装饰器基类,持有组件对象并转发请求。ConcreteDecorator
:具体装饰器,添加扩展功能(如加密)。
3. 现代C++实现示例
场景:网络数据流动态装饰
步骤1:定义抽象数据流接口
cpp
class DataStream {
public:
virtual ~DataStream() = default;
virtual void send(const std::string& data) = 0;
};
步骤2:实现基础数据流(明文传输)
cpp
class PlainStream : public DataStream {
public:
void send(const std::string& data) override {
std::cout << "发送明文: " << data << "\n";
}
};
步骤3:定义装饰器基类
cpp
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:实现具体装饰器(加密与压缩)
cpp
// 加密装饰器
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:客户端动态组合装饰器
cpp
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:日志消息装饰
cpp
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:图形界面控件装饰
cpp
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.批量处理优化:
cpp
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();
}
};