C++实现设计模式---装饰器模式 (Decorator)

news/2025/1/19 9:06:18/

装饰器模式 (Decorator)

装饰器模式 是一种结构型设计模式,它允许动态地将责任附加到对象上,既可以在运行时给一个对象添加功能,又不会影响其他对象的功能。


意图

  • 动态地扩展对象的功能。
  • 避免创建过多的子类,通过装饰器来“包装”对象,添加新功能。
  • 保持类的单一职责和开放封闭原则。

使用场景

  1. 系统需要动态地添加功能给对象
    • 如UI框架中的组件装饰,能动态增加功能(如窗口的滚动条、边框等)。
  2. 不希望通过继承来扩展对象功能
    • 继承可能会导致类的数量激增,装饰器模式能够解决这个问题。
  3. 功能扩展需要灵活控制
    • 可以在不同的对象上应用不同的装饰,不会互相影响。

参与者角色

  1. 组件接口 (Component)
    • 定义基本对象行为的接口,所有的装饰器和具体对象都需要实现此接口。
  2. 具体组件 (ConcreteComponent)
    • 具体实现基本行为的对象。
  3. 装饰器 (Decorator)
    • 持有组件的引用,并实现组件接口,增强功能。
  4. 具体装饰器 (ConcreteDecorator)
    • 通过调用被装饰对象的方法来添加额外功能。

示例代码

以下代码展示了如何使用装饰器模式扩展一个简单的咖啡类。

#include <iostream>
#include <string>// 组件接口
class Beverage {
public:virtual ~Beverage() = default;virtual std::string getDescription() const = 0;virtual double cost() const = 0;
};// 具体组件:咖啡
class Coffee : public Beverage {
public:std::string getDescription() const override {return "Coffee";}double cost() const override {return 5.0;}
};// 装饰器基类
class BeverageDecorator : public Beverage {
protected:Beverage* beverage;public:BeverageDecorator(Beverage* b) : beverage(b) {}virtual ~BeverageDecorator() = default;
};// 具体装饰器:加入牛奶
class MilkDecorator : public BeverageDecorator {
public:MilkDecorator(Beverage* b) : BeverageDecorator(b) {}std::string getDescription() const override {return beverage->getDescription() + ", Milk";}double cost() const override {return beverage->cost() + 1.0;}
};// 具体装饰器:加入糖
class SugarDecorator : public BeverageDecorator {
public:SugarDecorator(Beverage* b) : BeverageDecorator(b) {}std::string getDescription() const override {return beverage->getDescription() + ", Sugar";}double cost() const override {return beverage->cost() + 0.5;}
};// 客户端代码
int main() {Beverage* coffee = new Coffee();  // 创建基本的咖啡std::cout << coffee->getDescription() << " Cost: $" << coffee->cost() << std::endl;// 加入牛奶的装饰coffee = new MilkDecorator(coffee);std::cout << coffee->getDescription() << " Cost: $" << coffee->cost() << std::endl;// 再加入糖的装饰coffee = new SugarDecorator(coffee);std::cout << coffee->getDescription() << " Cost: $" << coffee->cost() << std::endl;// 清理内存delete coffee;return 0;
}

代码解析

1. 组件接口

  • Beverage 类是所有具体组件和装饰器的公共接口,定义了所有具体对象的行为:
class Beverage {
public:virtual ~Beverage() = default;virtual std::string getDescription() const = 0;virtual double cost() const = 0;
};

2. 具体组件

  • Coffee 是具体的组件,提供了描述和计算费用的功能:
class Coffee : public Beverage {
public:std::string getDescription() const override {return "Coffee";}double cost() const override {return 5.0;}
};

3. 装饰器基类

  • BeverageDecorator 继承了 Beverage,并持有一个 Beverage 对象,能够动态地扩展其功能:
class BeverageDecorator : public Beverage {
protected:Beverage* beverage;public:BeverageDecorator(Beverage* b) : beverage(b) {}virtual ~BeverageDecorator() = default;
};

4. 具体装饰器

  • MilkDecoratorSugarDecorator 是具体的装饰器类,分别增加了 MilkSugar 的功能:
class MilkDecorator : public BeverageDecorator {
public:MilkDecorator(Beverage* b) : BeverageDecorator(b) {}std::string getDescription() const override {return beverage->getDescription() + ", Milk";}double cost() const override {return beverage->cost() + 1.0;}
};
class SugarDecorator : public BeverageDecorator {
public:SugarDecorator(Beverage* b) : BeverageDecorator(b) {}std::string getDescription() const override {return beverage->getDescription() + ", Sugar";}double cost() const override {return beverage->cost() + 0.5;}
};

5. 客户端

  • 客户端可以按需为原始对象添加装饰,每次调用 getDescriptioncost 时,都能看到新添加的功能:
int main() {Beverage* coffee = new Coffee();  std::cout << coffee->getDescription() << " Cost: $" << coffee->cost() << std::endl;coffee = new MilkDecorator(coffee);std::cout << coffee->getDescription() << " Cost: $" << coffee->cost() << std::endl;coffee = new SugarDecorator(coffee);std::cout << coffee->getDescription() << " Cost: $" << coffee->cost() << std::endl;delete coffee;return 0;
}

优缺点

优点

  1. 动态扩展功能
    • 可以在运行时为对象添加新功能。
  2. 避免子类数量暴增
    • 通过装饰器而不是继承来扩展功能,避免了类的膨胀。
  3. 高灵活性
    • 可以灵活地为不同的对象选择不同的装饰器进行组合。

缺点

  1. 增加系统复杂性
    • 过多的装饰器可能使系统变得复杂,难以理解。
  2. 装饰器的顺序问题
    • 装饰器的顺序会影响最终对象的行为。

适用场景

  • 动态地给一个对象添加功能,例如为一个对象添加不同的用户界面样式、不同的服务功能。
  • 避免使用继承,需要在运行时动态地扩展功能。

总结

装饰器模式是一种非常灵活的模式,能够动态地给对象添加新功能,避免了继承带来的问题。通过组合装饰器类,能够灵活地为对象组合不同的功能,在很多场景中非常有用。



http://www.ppmy.cn/news/1564365.html

相关文章

upload-labs靶场练习

01&#xff08;JS前端认证&#xff09; 客户端JS脚本有限制&#xff0c;本来想用上次笔记的方法来做&#xff08;即改扩展名为.jpg&#xff0c;上传&#xff0c;抓包&#xff0c;改扩展名为.php&#xff0c;放行或者发送至repeater&#xff0c;改扩展名然后重发&#xff0c;再…

新星杯-ESP32智能硬件开发--ESP32系统

本博文内容导读&#x1f4d5;&#x1f389;&#x1f525; 1、ESP32芯片和系统架构进行描述&#xff0c;给出ESP32系统的地址映射规则。 2、介绍ESP32复位及时钟定时具体功能&#xff0c;方便后续开发。 3、介绍基于ESP32开发板使用的底层操作系统&#xff0c;对ESP32应用程序开…

基于 STM32 连接 Mini MP3 播放器的实践探索

在嵌入式系统开发中&#xff0c;音频播放功能常常是提升项目趣味性和实用性的关键要素之一。本文将详细阐述从选用 51 单片机到最终基于 STM32 成功连接 Mini MP3 播放器并实现串口通信及音频播放的全过程&#xff0c;旨在为面临类似技术难题的开发者提供参考与借鉴。 一、51 …

关于安科瑞Acrel-1000DP分布式光伏监控系统的实际案例分析-安科瑞 蒋静

摘 要&#xff1a;常规能源以煤、石油、天然气为主&#xff0c;不仅资源有限&#xff0c;而且会造成严重的大气污染&#xff0c;开发清洁的可再生能源已经成为当今发展的重要任务&#xff0c;“节能优先&#xff0c;效率为本”的分布式发电能源符合社会发展要求。 随着“双碳”…

SparkSQL数据源与数据存储综合实践

文章目录 1. 打开项目2. 查看数据集2.1 查看JSON格式数据2.2 查看CSV格式数据2.3 查看TXT格式数据 3. 添加单元测试依赖4. 创建数据加载与保存对象4.1 创建Spark会话对象4.2 创建加载JSON数据方法4.3 创建加载CSV数据方法4.4 创建加载Text数据方法4.5 创建加载JSON数据扩展方法…

第五章:VRRP和HSRP的网关冗余配置与管理

一、HRSP 1、简介 在骨干网的设备连接中&#xff0c;单一的设备容易出现故障造成网络的中断&#xff0c;可靠性较差&#xff0c;如图所示&#xff0c;如果核心交换机出现问题&#xff0c;不能正常工作&#xff0c;会影响整个网络的通信&#xff0c;因为整个网络的数据转发是通…

软件测试 —— Selenium(等待)

软件测试 —— Selenium&#xff08;等待&#xff09; 一个例子强制等待使用示例&#xff1a;为什么不推荐使用强制等待&#xff1f;更好的选择 隐式等待 implicitly_wait&#xff08;&#xff09;隐式等待和强制等待的区别隐式等待&#xff08;Implicit Wait&#xff09;强制等…

Jenkins-基于Role的鉴权机制

jenkins自带了一些全局性的安全配置。 但无法通过job等相对细粒度的来控制使用者的权限。但它可以借助相关的插件实现细颗粒的权限控制。 插件&#xff1a; Role-based Authorization Strategy 需要在configure global security中配置授权策略如下&#xff1a; 保存后&#x…