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

324 0
Honkers 2026-5-15 19:48:46 来自手机 | 显示全部楼层 |阅读模式

1. 模式定义

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

2. 核心特点

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

3. 模式结构

4. 应用场景

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

5. C++代码示例

基础示例:咖啡订单系统
  1. #include <iostream>
  2. #include <memory>
  3. #include <string>
  4. // 抽象组件:饮料
  5. class Beverage {
  6. public:
  7. virtual ~Beverage() = default;
  8. virtual std::string getDescription() const = 0;
  9. virtual double cost() const = 0;
  10. };
  11. // 具体组件:浓缩咖啡
  12. class Espresso : public Beverage {
  13. public:
  14. std::string getDescription() const override {
  15. return "浓缩咖啡";
  16. }
  17. double cost() const override {
  18. return 25.0;
  19. }
  20. };
  21. // 具体组件:混合咖啡
  22. class HouseBlend : public Beverage {
  23. public:
  24. std::string getDescription() const override {
  25. return "混合咖啡";
  26. }
  27. double cost() const override {
  28. return 20.0;
  29. }
  30. };
  31. // 抽象装饰类
  32. class CondimentDecorator : public Beverage {
  33. protected:
  34. std::unique_ptr<Beverage> beverage;
  35. public:
  36. CondimentDecorator(std::unique_ptr<Beverage> bev)
  37. : beverage(std::move(bev)) {}
  38. virtual ~CondimentDecorator() = default;
  39. std::string getDescription() const override {
  40. return beverage->getDescription();
  41. }
  42. double cost() const override {
  43. return beverage->cost();
  44. }
  45. };
  46. // 具体装饰:牛奶
  47. class Milk : public CondimentDecorator {
  48. public:
  49. Milk(std::unique_ptr<Beverage> bev)
  50. : CondimentDecorator(std::move(bev)) {}
  51. std::string getDescription() const override {
  52. return beverage->getDescription() + " + 牛奶";
  53. }
  54. double cost() const override {
  55. return beverage->cost() + 5.0;
  56. }
  57. };
  58. // 具体装饰:摩卡
  59. class Mocha : public CondimentDecorator {
  60. public:
  61. Mocha(std::unique_ptr<Beverage> bev)
  62. : CondimentDecorator(std::move(bev)) {}
  63. std::string getDescription() const override {
  64. return beverage->getDescription() + " + 摩卡";
  65. }
  66. double cost() const override {
  67. return beverage->cost() + 8.0;
  68. }
  69. };
  70. // 具体装饰:奶泡
  71. class Whip : public CondimentDecorator {
  72. public:
  73. Whip(std::unique_ptr<Beverage> bev)
  74. : CondimentDecorator(std::move(bev)) {}
  75. std::string getDescription() const override {
  76. return beverage->getDescription() + " + 奶泡";
  77. }
  78. double cost() const override {
  79. return beverage->cost() + 4.0;
  80. }
  81. };
  82. // 客户端使用
  83. int main() {
  84. // 一杯浓缩咖啡 + 双份牛奶
  85. auto beverage1 = std::make_unique<Espresso>();
  86. beverage1 = std::make_unique<Milk>(std::move(beverage1));
  87. beverage1 = std::make_unique<Milk>(std::move(beverage1));
  88. std::cout << "订单1: " << beverage1->getDescription()
  89. << " | 价格: ¥" << beverage1->cost() << std::endl;
  90. // 混合咖啡 + 摩卡 + 奶泡
  91. auto beverage2 = std::make_unique<HouseBlend>();
  92. beverage2 = std::make_unique<Mocha>(std::move(beverage2));
  93. beverage2 = std::make_unique<Whip>(std::move(beverage2));
  94. std::cout << "订单2: " << beverage2->getDescription()
  95. << " | 价格: ¥" << beverage2->cost() << std::endl;
  96. return 0;
  97. }
复制代码
高级示例:数据流处理
  1. #include <iostream>
  2. #include <string>
  3. #include <algorithm>
  4. // 抽象数据流
  5. class DataStream {
  6. public:
  7. virtual ~DataStream() = default;
  8. virtual std::string read() = 0;
  9. virtual void write(const std::string& data) = 0;
  10. };
  11. // 具体组件:文件流
  12. class FileStream : public DataStream {
  13. public:
  14. std::string read() override {
  15. return "原始文件数据";
  16. }
  17. void write(const std::string& data) override {
  18. std::cout << "写入文件: " << data << std::endl;
  19. }
  20. };
  21. // 抽象装饰器
  22. class StreamDecorator : public DataStream {
  23. protected:
  24. DataStream* stream;
  25. public:
  26. StreamDecorator(DataStream* s) : stream(s) {}
  27. virtual ~StreamDecorator() { delete stream; }
  28. std::string read() override {
  29. return stream->read();
  30. }
  31. void write(const std::string& data) override {
  32. stream->write(data);
  33. }
  34. };
  35. // 加密装饰器
  36. class EncryptionDecorator : public StreamDecorator {
  37. private:
  38. std::string encrypt(const std::string& data) {
  39. std::string encrypted = data;
  40. for (char& c : encrypted) {
  41. c = c ^ 0xFF; // 简单的异或加密
  42. }
  43. return encrypted;
  44. }
  45. std::string decrypt(const std::string& data) {
  46. return encrypt(data); // 异或两次恢复原值
  47. }
  48. public:
  49. EncryptionDecorator(DataStream* s) : StreamDecorator(s) {}
  50. std::string read() override {
  51. std::string data = StreamDecorator::read();
  52. return decrypt(data);
  53. }
  54. void write(const std::string& data) override {
  55. std::string encrypted = encrypt(data);
  56. StreamDecorator::write(encrypted);
  57. }
  58. };
  59. // 压缩装饰器
  60. class CompressionDecorator : public StreamDecorator {
  61. private:
  62. std::string compress(const std::string& data) {
  63. // 模拟压缩:重复字符计数
  64. std::string compressed;
  65. for (size_t i = 0; i < data.length(); ++i) {
  66. if (i == 0 || data[i] != data[i-1]) {
  67. compressed += data[i];
  68. }
  69. }
  70. return compressed;
  71. }
  72. std::string decompress(const std::string& data) {
  73. // 模拟解压(简单场景)
  74. return data;
  75. }
  76. public:
  77. CompressionDecorator(DataStream* s) : StreamDecorator(s) {}
  78. std::string read() override {
  79. std::string data = StreamDecorator::read();
  80. return decompress(data);
  81. }
  82. void write(const std::string& data) override {
  83. std::string compressed = compress(data);
  84. StreamDecorator::write(compressed);
  85. }
  86. };
  87. // 使用示例
  88. int main() {
  89. // 基础文件流
  90. DataStream* file = new FileStream();
  91. file->write("Hello World");
  92. // 添加加密功能
  93. DataStream* encrypted = new EncryptionDecorator(file);
  94. encrypted->write("Sensitive Data");
  95. // 添加压缩+加密功能
  96. DataStream* compressed = new CompressionDecorator(
  97. new EncryptionDecorator(new FileStream())
  98. );
  99. compressed->write("Important Content");
  100. delete compressed;
  101. delete encrypted;
  102. return 0;
  103. }
复制代码

6. 装饰模式 vs 继承

7. 优点与缺点

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

8. 最佳实践

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

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

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

9.1 为什么要结合?

9.2 结合方式

方式一:简单工厂 + 装饰模式
  1. #include <iostream>
  2. #include <memory>
  3. #include <string>
  4. #include <map>
  5. // 饮料基类
  6. class Beverage {
  7. public:
  8. virtual ~Beverage() = default;
  9. virtual std::string getDescription() const = 0;
  10. virtual double cost() const = 0;
  11. };
  12. // 具体饮料类
  13. class Espresso : public Beverage {
  14. public:
  15. std::string getDescription() const override { return "浓缩咖啡"; }
  16. double cost() const override { return 25.0; }
  17. };
  18. class Latte : public Beverage {
  19. public:
  20. std::string getDescription() const override { return "拿铁咖啡"; }
  21. double cost() const override { return 30.0; }
  22. };
  23. // 装饰器基类
  24. class CondimentDecorator : public Beverage {
  25. protected:
  26. std::unique_ptr<Beverage> beverage;
  27. public:
  28. CondimentDecorator(std::unique_ptr<Beverage> bev)
  29. : beverage(std::move(bev)) {}
  30. };
  31. // 具体装饰器
  32. class Milk : public CondimentDecorator {
  33. public:
  34. Milk(std::unique_ptr<Beverage> bev) : CondimentDecorator(std::move(bev)) {}
  35. std::string getDescription() const override {
  36. return beverage->getDescription() + " + 牛奶";
  37. }
  38. double cost() const override { return beverage->cost() + 5.0; }
  39. };
  40. class Mocha : public CondimentDecorator {
  41. public:
  42. Mocha(std::unique_ptr<Beverage> bev) : CondimentDecorator(std::move(bev)) {}
  43. std::string getDescription() const override {
  44. return beverage->getDescription() + " + 摩卡";
  45. }
  46. double cost() const override { return beverage->cost() + 8.0; }
  47. };
  48. // ========== 简单工厂 ==========
  49. class CoffeeFactory {
  50. public:
  51. enum CoffeeType { ESPRESSO, LATTE };
  52. static std::unique_ptr<Beverage> createCoffee(CoffeeType type) {
  53. switch (type) {
  54. case ESPRESSO: return std::make_unique<Espresso>();
  55. case LATTE: return std::make_unique<Latte>();
  56. default: return nullptr;
  57. }
  58. }
  59. // 预定义的组合
  60. static std::unique_ptr<Beverage> createSignatureLatte() {
  61. auto coffee = std::make_unique<Latte>();
  62. coffee = std::make_unique<Milk>(std::move(coffee));
  63. coffee = std::make_unique<Mocha>(std::move(coffee));
  64. return coffee;
  65. }
  66. };
  67. // 使用示例
  68. int main() {
  69. // 使用工厂创建基础咖啡
  70. auto coffee1 = CoffeeFactory::createCoffee(CoffeeFactory::ESPRESSO);
  71. coffee1 = std::make_unique<Milk>(std::move(coffee1));
  72. std::cout << coffee1->getDescription() << ": ¥" << coffee1->cost() << std::endl;
  73. // 使用工厂创建复杂组合
  74. auto signature = CoffeeFactory::createSignatureLatte();
  75. std::cout << signature->getDescription() << ": ¥" << signature->cost() << std::endl;
  76. return 0;
  77. }
复制代码
方式二:工厂方法 + 装饰模式
  1. #include <iostream>
  2. #include <memory>
  3. #include <vector>
  4. // 装饰器类型枚举
  5. enum class Topping { MILK, MOCHA, WHIP, SOY };
  6. // 抽象工厂
  7. class BeverageFactory {
  8. public:
  9. virtual ~BeverageFactory() = default;
  10. virtual std::unique_ptr<Beverage> createBeverage() = 0;
  11. virtual std::unique_ptr<Beverage> createWithToppings(
  12. const std::vector<Topping>& toppings) = 0;
  13. };
  14. // 具体工厂:浓缩咖啡工厂
  15. class EspressoFactory : public BeverageFactory {
  16. private:
  17. std::unique_ptr<Beverage> applyToppings(
  18. std::unique_ptr<Beverage> beverage,
  19. const std::vector<Topping>& toppings) {
  20. for (auto topping : toppings) {
  21. switch (topping) {
  22. case Topping::MILK:
  23. beverage = std::make_unique<Milk>(std::move(beverage));
  24. break;
  25. case Topping::MOCHA:
  26. beverage = std::make_unique<Mocha>(std::move(beverage));
  27. break;
  28. default:
  29. break;
  30. }
  31. }
  32. return beverage;
  33. }
  34. public:
  35. std::unique_ptr<Beverage> createBeverage() override {
  36. return std::make_unique<Espresso>();
  37. }
  38. std::unique_ptr<Beverage> createWithToppings(
  39. const std::vector<Topping>& toppings) override {
  40. auto beverage = createBeverage();
  41. return applyToppings(std::move(beverage), toppings);
  42. }
  43. };
  44. // 使用示例
  45. int main() {
  46. EspressoFactory factory;
  47. // 创建纯浓缩咖啡
  48. auto espresso = factory.createBeverage();
  49. // 创建加牛奶和摩卡的浓缩咖啡
  50. auto deluxe = factory.createWithToppings({Topping::MILK, Topping::MOCHA});
  51. std::cout << deluxe->getDescription() << ": ¥" << deluxe->cost() << std::endl;
  52. return 0;
  53. }
复制代码
方式三:抽象工厂 + 装饰模式
  1. #include <iostream>
  2. #include <memory>
  3. #include <map>
  4. #include <functional>
  5. // 装饰器创建函数类型
  6. using DecoratorCreator = std::function<std::unique_ptr<Beverage>(std::unique_ptr<Beverage>)>;
  7. // 装饰器注册表
  8. class DecoratorRegistry {
  9. private:
  10. std::map<std::string, DecoratorCreator> creators;
  11. public:
  12. void registerDecorator(const std::string& name, DecoratorCreator creator) {
  13. creators[name] = creator;
  14. }
  15. DecoratorCreator getCreator(const std::string& name) {
  16. auto it = creators.find(name);
  17. if (it != creators.end()) {
  18. return it->second;
  19. }
  20. return nullptr;
  21. }
  22. };
  23. // 全局注册表
  24. DecoratorRegistry& getRegistry() {
  25. static DecoratorRegistry registry;
  26. return registry;
  27. }
  28. // 自动注册类
  29. class AutoRegister {
  30. public:
  31. AutoRegister(const std::string& name, DecoratorCreator creator) {
  32. getRegistry().registerDecorator(name, creator);
  33. }
  34. };
  35. // 注册装饰器(使用静态初始化)
  36. static AutoRegister registerMilk("milk", [](std::unique_ptr<Beverage> b) {
  37. return std::make_unique<Milk>(std::move(b));
  38. });
  39. static AutoRegister registerMocha("mocha", [](std::unique_ptr<Beverage> b) {
  40. return std::make_unique<Mocha>(std::move(b));
  41. });
  42. // 抽象工厂:支持配置驱动
  43. class ConfigurableCoffeeFactory {
  44. private:
  45. std::string baseCoffee;
  46. std::vector<std::string> toppings;
  47. public:
  48. ConfigurableCoffeeFactory(const std::string& coffee,
  49. const std::vector<std::string>& toppings)
  50. : baseCoffee(coffee), toppings(toppings) {}
  51. std::unique_ptr<Beverage> create() {
  52. std::unique_ptr<Beverage> beverage;
  53. // 创建基础咖啡
  54. if (baseCoffee == "espresso") {
  55. beverage = std::make_unique<Espresso>();
  56. } else if (baseCoffee == "latte") {
  57. beverage = std::make_unique<Latte>();
  58. } else {
  59. return nullptr;
  60. }
  61. // 动态应用装饰器
  62. for (const auto& topping : toppings) {
  63. auto creator = getRegistry().getCreator(topping);
  64. if (creator) {
  65. beverage = creator(std::move(beverage));
  66. }
  67. }
  68. return beverage;
  69. }
  70. };
  71. // 使用示例:类似配置文件解析
  72. int main() {
  73. // 模拟从配置文件读取
  74. std::map<std::string, std::vector<std::string>> orders = {
  75. {"order1", {"espresso", "milk", "mocha"}},
  76. {"order2", {"latte", "milk"}},
  77. {"order3", {"espresso", "milk", "milk", "mocha"}} // 双份牛奶
  78. };
  79. for (const auto& [orderId, config] : orders) {
  80. if (config.size() < 1) continue;
  81. std::string coffeeType = config[0];
  82. std::vector<std::string> toppings(config.begin() + 1, config.end());
  83. ConfigurableCoffeeFactory factory(coffeeType, toppings);
  84. auto beverage = factory.create();
  85. if (beverage) {
  86. std::cout << orderId << ": " << beverage->getDescription()
  87. << " | ¥" << beverage->cost() << std::endl;
  88. }
  89. }
  90. return 0;
  91. }
复制代码
方式四:建造者模式结合
  1. #include <iostream>
  2. #include <memory>
  3. #include <vector>
  4. // 装饰器构建器
  5. class CoffeeBuilder {
  6. private:
  7. std::unique_ptr<Beverage> beverage;
  8. public:
  9. CoffeeBuilder& setBase(std::unique_ptr<Beverage> base) {
  10. beverage = std::move(base);
  11. return *this;
  12. }
  13. CoffeeBuilder& addMilk() {
  14. if (beverage) {
  15. beverage = std::make_unique<Milk>(std::move(beverage));
  16. }
  17. return *this;
  18. }
  19. CoffeeBuilder& addMocha() {
  20. if (beverage) {
  21. beverage = std::make_unique<Mocha>(std::move(beverage));
  22. }
  23. return *this;
  24. }
  25. CoffeeBuilder& addWhip() {
  26. if (beverage) {
  27. beverage = std::make_unique<Whip>(std::move(beverage));
  28. }
  29. return *this;
  30. }
  31. std::unique_ptr<Beverage> build() {
  32. return std::move(beverage);
  33. }
  34. };
  35. // 工厂类使用建造者
  36. class CoffeeShop {
  37. public:
  38. static std::unique_ptr<Beverage> createStandardLatte() {
  39. return CoffeeBuilder()
  40. .setBase(std::make_unique<Latte>())
  41. .addMilk()
  42. .build();
  43. }
  44. static std::unique_ptr<Beverage> createDeluxeMocha() {
  45. return CoffeeBuilder()
  46. .setBase(std::make_unique<Espresso>())
  47. .addMilk()
  48. .addMocha()
  49. .addWhip()
  50. .build();
  51. }
  52. // 支持自定义
  53. static std::unique_ptr<Beverage> customOrder(
  54. std::unique_ptr<Beverage> base,
  55. bool hasMilk, bool hasMocha, bool hasWhip) {
  56. CoffeeBuilder builder;
  57. builder.setBase(std::move(base));
  58. if (hasMilk) builder.addMilk();
  59. if (hasMocha) builder.addMocha();
  60. if (hasWhip) builder.addWhip();
  61. return builder.build();
  62. }
  63. };
  64. int main() {
  65. auto latte = CoffeeShop::createStandardLatte();
  66. std::cout << latte->getDescription() << ": ¥" << latte->cost() << std::endl;
  67. auto mocha = CoffeeShop::createDeluxeMocha();
  68. std::cout << mocha->getDescription() << ": ¥" << mocha->cost() << std::endl;
  69. auto custom = CoffeeShop::customOrder(
  70. std::make_unique<Latte>(),
  71. true, true, false // 加牛奶和摩卡,不加奶泡
  72. );
  73. std::cout << custom->getDescription() << ": ¥" << custom->cost() << std::endl;
  74. return 0;
  75. }
复制代码

3. 结合的优势对比

4. 最佳实践建议

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

5. 实际应用场景

  1. // 实战:UI组件装饰工厂
  2. class UIComponentFactory {
  3. public:
  4. static std::unique_ptr<Component> createStyledButton(
  5. const std::string& text,
  6. const std::vector<std::string>& styles) {
  7. auto button = std::make_unique<Button>(text);
  8. for (const auto& style : styles) {
  9. if (style == "border") {
  10. button = std::make_unique<BorderDecorator>(std::move(button));
  11. } else if (style == "shadow") {
  12. button = std::make_unique<ShadowDecorator>(std::move(button));
  13. } else if (style == "rounded") {
  14. button = std::make_unique<RoundedDecorator>(std::move(button));
  15. }
  16. }
  17. return button;
  18. }
  19. };
  20. // 使用
  21. auto btn = UIComponentFactory::createStyledButton("Click Me",
  22. {"border", "shadow", "rounded"});
复制代码

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

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行