【C++设计模式】第九篇:装饰器模式(Decorator)

注意:复现代码时,确保 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()      |  
+---------------------+    +--------------------+ +--------------------+  

角色说明

  1. Component:抽象接口,定义核心功能方法(如send())。
  2. ​ConcreteComponent:具体组件,实现基础功能(如明文数据发送)。
  3. Decorator:装饰器基类,持有组件对象并转发请求。
  4. 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();  
    }  
};  
相关推荐
eurotruck9 分钟前
c++贪吃蛇V1.0
开发语言·c++·贪吃蛇
Android系统攻城狮41 分钟前
C++进阶之操作符重载函数operator[]:用法实例(四百三十五)
开发语言·c++
liulilittle1 小时前
VGW 虚拟路由器ARP剖析
开发语言·c++·编程语言·路由·sd·sdn·vgw
庸了个白1 小时前
一种面向 AIoT 定制化场景的服务架构设计方案
mqtt·设计模式·系统架构·aiot·物联网平台·动态配置·解耦设计
Juan_20122 小时前
P1040题解
c++·算法·动态规划·题解
Onesoft%J1ao2 小时前
C++竞赛递推算法-斐波那契数列常见题型与例题详解
c++·算法·动态规划·递推·信息学奥赛
黄昏晓x2 小时前
C++----多态
java·jvm·c++
。TAT。3 小时前
C++ - List
数据结构·c++·学习
小龙报4 小时前
《算法通关指南---C++编程篇(2)》
c语言·开发语言·数据结构·c++·程序人生·算法·学习方法
王夏奇5 小时前
C++友元函数和友元类!
开发语言·c++