06.C++设计模式-装饰模式

1. 模式定义

装饰模式(Decorator Pattern)是一种结构型设计模式 ,允许动态地 向一个现有对象添加新的功能,同时不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供额外的功能。

2. 核心特点

  • 替代继承:提供比继承更灵活的扩展方式
  • 透明性:装饰类与被装饰类具有相同的接口
  • 动态性:运行时动态添加/撤销功能
  • 开闭原则:对扩展开放,对修改关闭

3. 模式结构

<<interface>>
Component
+operation() : string
ConcreteComponent
+operation() : string
Decorator
-component: Component
+Decorator(Component* comp)
+operation() : string
ConcreteDecoratorA
-addedState: string
+operation() : string
+addedBehavior() : string
ConcreteDecoratorB
+operation() : string
+addedBehavior() : string

4. 应用场景

典型场景:
  1. IO流处理(Java/C++流库)
  2. GUI组件(添加滚动条、边框等)
  3. 咖啡/披萨订单系统(添加配料)
  4. 权限系统(动态添加角色权限)
  5. 日志系统(不同格式/输出方式)
  6. 数据压缩/加密(透明附加功能)
实战案例:
  • 游戏装备系统(武器附魔)
  • 文本编辑器(字体、颜色、下划线等格式)
  • 图片处理(滤镜、水印、边框)

5. C++代码示例

基础示例:咖啡订单系统
cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

// 抽象组件:饮料
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 "浓缩咖啡";
    }
    
    double cost() const override {
        return 25.0;
    }
};

// 具体组件:混合咖啡
class HouseBlend : public Beverage {
public:
    std::string getDescription() const override {
        return "混合咖啡";
    }
    
    double cost() const override {
        return 20.0;
    }
};

// 抽象装饰类
class CondimentDecorator : public Beverage {
protected:
    std::unique_ptr<Beverage> beverage;
    
public:
    CondimentDecorator(std::unique_ptr<Beverage> bev) 
        : beverage(std::move(bev)) {}
    
    virtual ~CondimentDecorator() = default;
    
    std::string getDescription() const override {
        return beverage->getDescription();
    }
    
    double cost() const override {
        return beverage->cost();
    }
};

// 具体装饰:牛奶
class Milk : public CondimentDecorator {
public:
    Milk(std::unique_ptr<Beverage> bev) 
        : CondimentDecorator(std::move(bev)) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + " + 牛奶";
    }
    
    double cost() const override {
        return beverage->cost() + 5.0;
    }
};

// 具体装饰:摩卡
class Mocha : public CondimentDecorator {
public:
    Mocha(std::unique_ptr<Beverage> bev) 
        : CondimentDecorator(std::move(bev)) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + " + 摩卡";
    }
    
    double cost() const override {
        return beverage->cost() + 8.0;
    }
};

// 具体装饰:奶泡
class Whip : public CondimentDecorator {
public:
    Whip(std::unique_ptr<Beverage> bev) 
        : CondimentDecorator(std::move(bev)) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + " + 奶泡";
    }
    
    double cost() const override {
        return beverage->cost() + 4.0;
    }
};

// 客户端使用
int main() {
    // 一杯浓缩咖啡 + 双份牛奶
    auto beverage1 = std::make_unique<Espresso>();
    beverage1 = std::make_unique<Milk>(std::move(beverage1));
    beverage1 = std::make_unique<Milk>(std::move(beverage1));
    
    std::cout << "订单1: " << beverage1->getDescription() 
              << " | 价格: ¥" << beverage1->cost() << std::endl;
    
    // 混合咖啡 + 摩卡 + 奶泡
    auto beverage2 = std::make_unique<HouseBlend>();
    beverage2 = std::make_unique<Mocha>(std::move(beverage2));
    beverage2 = std::make_unique<Whip>(std::move(beverage2));
    
    std::cout << "订单2: " << beverage2->getDescription() 
              << " | 价格: ¥" << beverage2->cost() << std::endl;
    
    return 0;
}
高级示例:数据流处理
cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>

// 抽象数据流
class DataStream {
public:
    virtual ~DataStream() = default;
    virtual std::string read() = 0;
    virtual void write(const std::string& data) = 0;
};

// 具体组件:文件流
class FileStream : public DataStream {
public:
    std::string read() override {
        return "原始文件数据";
    }
    
    void write(const std::string& data) override {
        std::cout << "写入文件: " << data << std::endl;
    }
};

// 抽象装饰器
class StreamDecorator : public DataStream {
protected:
    DataStream* stream;
    
public:
    StreamDecorator(DataStream* s) : stream(s) {}
    virtual ~StreamDecorator() { delete stream; }
    
    std::string read() override {
        return stream->read();
    }
    
    void write(const std::string& data) override {
        stream->write(data);
    }
};

// 加密装饰器
class EncryptionDecorator : public StreamDecorator {
private:
    std::string encrypt(const std::string& data) {
        std::string encrypted = data;
        for (char& c : encrypted) {
            c = c ^ 0xFF;  // 简单的异或加密
        }
        return encrypted;
    }
    
    std::string decrypt(const std::string& data) {
        return encrypt(data);  // 异或两次恢复原值
    }
    
public:
    EncryptionDecorator(DataStream* s) : StreamDecorator(s) {}
    
    std::string read() override {
        std::string data = StreamDecorator::read();
        return decrypt(data);
    }
    
    void write(const std::string& data) override {
        std::string encrypted = encrypt(data);
        StreamDecorator::write(encrypted);
    }
};

// 压缩装饰器
class CompressionDecorator : public StreamDecorator {
private:
    std::string compress(const std::string& data) {
        // 模拟压缩:重复字符计数
        std::string compressed;
        for (size_t i = 0; i < data.length(); ++i) {
            if (i == 0 || data[i] != data[i-1]) {
                compressed += data[i];
            }
        }
        return compressed;
    }
    
    std::string decompress(const std::string& data) {
        // 模拟解压(简单场景)
        return data;
    }
    
public:
    CompressionDecorator(DataStream* s) : StreamDecorator(s) {}
    
    std::string read() override {
        std::string data = StreamDecorator::read();
        return decompress(data);
    }
    
    void write(const std::string& data) override {
        std::string compressed = compress(data);
        StreamDecorator::write(compressed);
    }
};

// 使用示例
int main() {
    // 基础文件流
    DataStream* file = new FileStream();
    file->write("Hello World");
    
    // 添加加密功能
    DataStream* encrypted = new EncryptionDecorator(file);
    encrypted->write("Sensitive Data");
    
    // 添加压缩+加密功能
    DataStream* compressed = new CompressionDecorator(
        new EncryptionDecorator(new FileStream())
    );
    compressed->write("Important Content");
    
    delete compressed;
    delete encrypted;
    
    return 0;
}

6. 装饰模式 vs 继承

装饰模式
核心组件
装饰器1
装饰器2
装饰器3
继承方式
父类
子类1
子类2
子类3
孙类1-1
孙类1-2

7. 优点与缺点

优点 ✅
  • 灵活性:运行时动态添加/删除功能
  • 避免类爆炸:无需为每个组合创建子类
  • 单一职责:每个装饰类只负责一个功能
  • 组合优于继承:更符合设计原则
缺点 ❌
  • 增加复杂度:产生大量小类
  • 调试困难:层层包装,追踪较难
  • 类型识别问题:装饰后的对象类型发生变化

8. 最佳实践

  1. 保持接口一致:装饰类必须实现被装饰类的接口
  2. 避免过度装饰:装饰链不要超过3-4层
  3. 考虑使用工厂模式:创建复杂的装饰组合
  4. 注意性能影响:每层装饰都有额外开销

9.装饰模式与工厂模式的结合

装饰模式和工厂模式的结合是一种常见的设计模式组合,可以有效解决装饰对象的创建和管理问题。

9.1 为什么要结合?

客户端
直接创建装饰对象
问题1: 创建逻辑分散
问题2: 容易出错
问题3: 难以统一管理
工厂模式
解决方案
集中创建逻辑
保证正确性
简化客户端代码

9.2 结合方式

方式一:简单工厂 + 装饰模式
cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
#include <map>

// 饮料基类
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 "浓缩咖啡"; }
    double cost() const override { return 25.0; }
};

class Latte : public Beverage {
public:
    std::string getDescription() const override { return "拿铁咖啡"; }
    double cost() const override { return 30.0; }
};

// 装饰器基类
class CondimentDecorator : public Beverage {
protected:
    std::unique_ptr<Beverage> beverage;
public:
    CondimentDecorator(std::unique_ptr<Beverage> bev) 
        : beverage(std::move(bev)) {}
};

// 具体装饰器
class Milk : public CondimentDecorator {
public:
    Milk(std::unique_ptr<Beverage> bev) : CondimentDecorator(std::move(bev)) {}
    std::string getDescription() const override { 
        return beverage->getDescription() + " + 牛奶"; 
    }
    double cost() const override { return beverage->cost() + 5.0; }
};

class Mocha : public CondimentDecorator {
public:
    Mocha(std::unique_ptr<Beverage> bev) : CondimentDecorator(std::move(bev)) {}
    std::string getDescription() const override { 
        return beverage->getDescription() + " + 摩卡"; 
    }
    double cost() const override { return beverage->cost() + 8.0; }
};

// ========== 简单工厂 ==========
class CoffeeFactory {
public:
    enum CoffeeType { ESPRESSO, LATTE };
    
    static std::unique_ptr<Beverage> createCoffee(CoffeeType type) {
        switch (type) {
            case ESPRESSO: return std::make_unique<Espresso>();
            case LATTE: return std::make_unique<Latte>();
            default: return nullptr;
        }
    }
    
    // 预定义的组合
    static std::unique_ptr<Beverage> createSignatureLatte() {
        auto coffee = std::make_unique<Latte>();
        coffee = std::make_unique<Milk>(std::move(coffee));
        coffee = std::make_unique<Mocha>(std::move(coffee));
        return coffee;
    }
};

// 使用示例
int main() {
    // 使用工厂创建基础咖啡
    auto coffee1 = CoffeeFactory::createCoffee(CoffeeFactory::ESPRESSO);
    coffee1 = std::make_unique<Milk>(std::move(coffee1));
    std::cout << coffee1->getDescription() << ": ¥" << coffee1->cost() << std::endl;
    
    // 使用工厂创建复杂组合
    auto signature = CoffeeFactory::createSignatureLatte();
    std::cout << signature->getDescription() << ": ¥" << signature->cost() << std::endl;
    
    return 0;
}
方式二:工厂方法 + 装饰模式
cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>

// 装饰器类型枚举
enum class Topping { MILK, MOCHA, WHIP, SOY };

// 抽象工厂
class BeverageFactory {
public:
    virtual ~BeverageFactory() = default;
    virtual std::unique_ptr<Beverage> createBeverage() = 0;
    virtual std::unique_ptr<Beverage> createWithToppings(
        const std::vector<Topping>& toppings) = 0;
};

// 具体工厂:浓缩咖啡工厂
class EspressoFactory : public BeverageFactory {
private:
    std::unique_ptr<Beverage> applyToppings(
        std::unique_ptr<Beverage> beverage,
        const std::vector<Topping>& toppings) {
        
        for (auto topping : toppings) {
            switch (topping) {
                case Topping::MILK:
                    beverage = std::make_unique<Milk>(std::move(beverage));
                    break;
                case Topping::MOCHA:
                    beverage = std::make_unique<Mocha>(std::move(beverage));
                    break;
                default:
                    break;
            }
        }
        return beverage;
    }
    
public:
    std::unique_ptr<Beverage> createBeverage() override {
        return std::make_unique<Espresso>();
    }
    
    std::unique_ptr<Beverage> createWithToppings(
        const std::vector<Topping>& toppings) override {
        auto beverage = createBeverage();
        return applyToppings(std::move(beverage), toppings);
    }
};

// 使用示例
int main() {
    EspressoFactory factory;
    
    // 创建纯浓缩咖啡
    auto espresso = factory.createBeverage();
    
    // 创建加牛奶和摩卡的浓缩咖啡
    auto deluxe = factory.createWithToppings({Topping::MILK, Topping::MOCHA});
    
    std::cout << deluxe->getDescription() << ": ¥" << deluxe->cost() << std::endl;
    
    return 0;
}
方式三:抽象工厂 + 装饰模式
cpp 复制代码
#include <iostream>
#include <memory>
#include <map>
#include <functional>

// 装饰器创建函数类型
using DecoratorCreator = std::function<std::unique_ptr<Beverage>(std::unique_ptr<Beverage>)>;

// 装饰器注册表
class DecoratorRegistry {
private:
    std::map<std::string, DecoratorCreator> creators;
    
public:
    void registerDecorator(const std::string& name, DecoratorCreator creator) {
        creators[name] = creator;
    }
    
    DecoratorCreator getCreator(const std::string& name) {
        auto it = creators.find(name);
        if (it != creators.end()) {
            return it->second;
        }
        return nullptr;
    }
};

// 全局注册表
DecoratorRegistry& getRegistry() {
    static DecoratorRegistry registry;
    return registry;
}

// 自动注册类
class AutoRegister {
public:
    AutoRegister(const std::string& name, DecoratorCreator creator) {
        getRegistry().registerDecorator(name, creator);
    }
};

// 注册装饰器(使用静态初始化)
static AutoRegister registerMilk("milk", [](std::unique_ptr<Beverage> b) {
    return std::make_unique<Milk>(std::move(b));
});

static AutoRegister registerMocha("mocha", [](std::unique_ptr<Beverage> b) {
    return std::make_unique<Mocha>(std::move(b));
});

// 抽象工厂:支持配置驱动
class ConfigurableCoffeeFactory {
private:
    std::string baseCoffee;
    std::vector<std::string> toppings;
    
public:
    ConfigurableCoffeeFactory(const std::string& coffee, 
                              const std::vector<std::string>& toppings)
        : baseCoffee(coffee), toppings(toppings) {}
    
    std::unique_ptr<Beverage> create() {
        std::unique_ptr<Beverage> beverage;
        
        // 创建基础咖啡
        if (baseCoffee == "espresso") {
            beverage = std::make_unique<Espresso>();
        } else if (baseCoffee == "latte") {
            beverage = std::make_unique<Latte>();
        } else {
            return nullptr;
        }
        
        // 动态应用装饰器
        for (const auto& topping : toppings) {
            auto creator = getRegistry().getCreator(topping);
            if (creator) {
                beverage = creator(std::move(beverage));
            }
        }
        
        return beverage;
    }
};

// 使用示例:类似配置文件解析
int main() {
    // 模拟从配置文件读取
    std::map<std::string, std::vector<std::string>> orders = {
        {"order1", {"espresso", "milk", "mocha"}},
        {"order2", {"latte", "milk"}},
        {"order3", {"espresso", "milk", "milk", "mocha"}}  // 双份牛奶
    };
    
    for (const auto& [orderId, config] : orders) {
        if (config.size() < 1) continue;
        
        std::string coffeeType = config[0];
        std::vector<std::string> toppings(config.begin() + 1, config.end());
        
        ConfigurableCoffeeFactory factory(coffeeType, toppings);
        auto beverage = factory.create();
        
        if (beverage) {
            std::cout << orderId << ": " << beverage->getDescription() 
                      << " | ¥" << beverage->cost() << std::endl;
        }
    }
    
    return 0;
}
方式四:建造者模式结合
cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>

// 装饰器构建器
class CoffeeBuilder {
private:
    std::unique_ptr<Beverage> beverage;
    
public:
    CoffeeBuilder& setBase(std::unique_ptr<Beverage> base) {
        beverage = std::move(base);
        return *this;
    }
    
    CoffeeBuilder& addMilk() {
        if (beverage) {
            beverage = std::make_unique<Milk>(std::move(beverage));
        }
        return *this;
    }
    
    CoffeeBuilder& addMocha() {
        if (beverage) {
            beverage = std::make_unique<Mocha>(std::move(beverage));
        }
        return *this;
    }
    
    CoffeeBuilder& addWhip() {
        if (beverage) {
            beverage = std::make_unique<Whip>(std::move(beverage));
        }
        return *this;
    }
    
    std::unique_ptr<Beverage> build() {
        return std::move(beverage);
    }
};

// 工厂类使用建造者
class CoffeeShop {
public:
    static std::unique_ptr<Beverage> createStandardLatte() {
        return CoffeeBuilder()
            .setBase(std::make_unique<Latte>())
            .addMilk()
            .build();
    }
    
    static std::unique_ptr<Beverage> createDeluxeMocha() {
        return CoffeeBuilder()
            .setBase(std::make_unique<Espresso>())
            .addMilk()
            .addMocha()
            .addWhip()
            .build();
    }
    
    // 支持自定义
    static std::unique_ptr<Beverage> customOrder(
        std::unique_ptr<Beverage> base,
        bool hasMilk, bool hasMocha, bool hasWhip) {
        
        CoffeeBuilder builder;
        builder.setBase(std::move(base));
        
        if (hasMilk) builder.addMilk();
        if (hasMocha) builder.addMocha();
        if (hasWhip) builder.addWhip();
        
        return builder.build();
    }
};

int main() {
    auto latte = CoffeeShop::createStandardLatte();
    std::cout << latte->getDescription() << ": ¥" << latte->cost() << std::endl;
    
    auto mocha = CoffeeShop::createDeluxeMocha();
    std::cout << mocha->getDescription() << ": ¥" << mocha->cost() << std::endl;
    
    auto custom = CoffeeShop::customOrder(
        std::make_unique<Latte>(), 
        true, true, false  // 加牛奶和摩卡,不加奶泡
    );
    std::cout << custom->getDescription() << ": ¥" << custom->cost() << std::endl;
    
    return 0;
}

3. 结合的优势对比

使用工厂
客户端
Factory.create
自动应用装饰器
返回完整对象
不使用工厂
客户端
new Espresso
new Milk
new Mocha
...

4. 最佳实践建议

场景 推荐方式 原因
装饰器种类少(<5种) 简单工厂 实现简单,够用
装饰器有层次关系 工厂方法 支持继承扩展
需要灵活配置 抽象工厂+注册表 配置驱动,热插拔
复杂构建过程 建造者模式 链式调用,可读性强

5. 实际应用场景

cpp 复制代码
// 实战:UI组件装饰工厂
class UIComponentFactory {
public:
    static std::unique_ptr<Component> createStyledButton(
        const std::string& text,
        const std::vector<std::string>& styles) {
        
        auto button = std::make_unique<Button>(text);
        
        for (const auto& style : styles) {
            if (style == "border") {
                button = std::make_unique<BorderDecorator>(std::move(button));
            } else if (style == "shadow") {
                button = std::make_unique<ShadowDecorator>(std::move(button));
            } else if (style == "rounded") {
                button = std::make_unique<RoundedDecorator>(std::move(button));
            }
        }
        
        return button;
    }
};

// 使用
auto btn = UIComponentFactory::createStyledButton("Click Me", 
                                                   {"border", "shadow", "rounded"});

这种结合方式既保持了装饰模式的灵活性,又通过工厂模式解决了对象创建的复杂度问题,是实际项目中的常用组合。

相关推荐
宏笋1 小时前
C++11使用chrono获取当前时间戳
c++
Shadow(⊙o⊙)1 小时前
硬核手搓解析!进程-内核分析:命令行参数及环境变量,重构main()
linux·运维·服务器·开发语言·c++·后端·学习
YYYing.1 小时前
【C++项目之高并发内存池 (五)】一些小细节和性能优化及整体测试
c++·性能优化·高并发·内存池·基数树
2301_789015621 小时前
Linux:基础指令(二)
linux·运维·服务器·c语言·开发语言·c++·算法
闻缺陷则喜何志丹1 小时前
【区间合并】P7912 [CSP-J 2021] 小熊的果篮|普及+
c++·算法·洛谷·区间合并
悟05152 小时前
设计模式-策略模式
设计模式·策略模式
REDcker10 小时前
C++变量存储与ELF段布局详解 从const全局到rodata与nm_readelf验证实践
java·c++·面试
UXbot12 小时前
一人独立交付 UI + 前端:AI 驱动 UI 设计工具的五大功能模块深度评测
前端·低代码·ui·设计模式·交互
王老师青少年编程13 小时前
csp信奥赛C++高频考点专项训练之字符串 --【字符串排序】:合并序列
c++·字符串·csp·高频考点·信奥赛·字符串排序·合并序列