C++设计模式-装饰器模式 原创 设计模式 2021年10月23日 23:01 夏至未至 996 当前内容 7466 字,在路上,马上到,马上到 ### 目录 [TOC] ### 装饰器模式介绍 #### 何为装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活,这种类型的设计模式属于结构型模式,`它是作为现有的类的一个包装`。 #### 为何使用装饰器模式 一般情况,扩展一个类的功能会使用继承方式来实现。但继承耦合度高,并且随着扩展功能的增多,子类会很臃肿。如果使用`组合关系`来创建一个包装对象(即装饰对象)来`包裹真实对象`,并在`保持真实对象的类结构不变`的前提下,为其提供额外的功能,这就是装饰模式的目标。 #### 如何实现装饰器模式 使用`组合关系来创建一个包装对象`来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能。 #### 装饰器模式核心 装饰模式的核心在于抽象装饰类的设计,抽象装饰类(装饰器类)和原始类继承同样的父类,这样可以对原始类`嵌套`多个装饰器类。抽象装饰类(装饰器类)是对功能的增强,这也是装饰器模式应用场景的一个重要特点。并且抽象装饰类维持一个对抽象构件对象的引用component,抽象装饰类可以通过构造函数或Setter方法注入一个抽象构件类型的对象。 ### 装饰器模式应用场景 1. 在不影响其他对象的情况下,给单个对象动态扩展职责; 2. 不适宜采用继承的方式进行扩展的时候,可以考虑使用装饰模式。 ### 模式特点 #### 优点 1. 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。 2. 可以通过一种动态的方式来扩展一个对象的功能。 3. 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合进行多次装饰。 4. 具体构件类与具体装饰类可以独立变化,符合“开闭原则”。 #### 缺点 1. 装饰模式中会增加很多小的对象,对象的区别主要在于各种装饰的连接方式不同,而并不是职责不同,大量小对象的产生会占用较多的系统资源; 2. 装饰模式比继承模式更灵活,但也更容易出错,更难于排错。 ### 模式角色类 - Component(抽象构件): 它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,使客户端能够以一致的方式处理未被装饰的对象以及装饰之后的对象。 - ConcreteComponent(具体构件): 它是抽象构件类的子类,实现了在抽象构件中声明的方法,装饰器就是为它增加额外的功能(方法)。 - Decorator(抽象装饰类): 它也是抽象构件类的子类,用于给具体构件增加功能,但是具体功能在它的子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用构件对象的方法,并通过其子类(具体装饰类)扩展该方法,以达到装饰的目的。 - ConcreteDecorator(具体装饰类): 它是抽象装饰类的子类,负责向构件添加新的功能。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。 ### 上机实操 #### 代码场景 奥迪rsQ8低配 150万,高配200万,这是两个标配,还可以改激光大灯20万,改8涡轮增压30万,改雪地胎10万,然后别人来买车 - Component(抽象构件): ConfigureCar - ConcreteComponent(具体构件): ConcreteConfigureCar - Decorator(抽象装饰类):Decorator - ConcreteDecorator(具体装饰类):addLaserHeadLights , add8Turbo , changeSnowtires #### 代码 #include #include #include #include #include // 场景:奥迪rsQ8低配 150万,高配200万,这是两个标配,还可以改激光大灯20万,改8涡轮增压30万,改雪地胎10万 // Component(抽象构件) // ConfigureCar 配置你的爱车 class ConfigureCar { public: virtual ~ConfigureCar() = default; // 配置这辆车 virtual std::string ConfigureTheCar() = 0; // 计算配置过后汽车价格 virtual float CalculatePrice() = 0; protected: ConfigureCar() = default; }; // ConcreteComponent(具体构件) enum TYPE { // 标配150万 Base150 = 150, // 标配200万 Base200 = 200, }; // ConcreteConfigureCar class ConcreteConfigureCar : public ConfigureCar { public: explicit ConcreteConfigureCar(TYPE price) { std::cout << "车辆开始配置" << std::endl; basePrice = price; } ~ConcreteConfigureCar() override { std::cout << "车辆结束配置" << std::endl; } std::string ConfigureTheCar() override { std::stringstream buf; buf.precision(2); buf.setf(std::ios::fixed); buf << basePrice; std::string str; str = buf.str(); return "标配" + str + "元奥迪RS Q8"; } float CalculatePrice() override { return basePrice; } private: float basePrice; }; // Decorator(抽象装饰类) // Decorator class Decorator : public ConfigureCar { public: explicit Decorator(ConfigureCar* configureCar) { this->configureCar = configureCar; } ~Decorator() override { delete configureCar; }; std::string ConfigureTheCar() override { return configureCar->ConfigureTheCar(); } float CalculatePrice() override { return configureCar->CalculatePrice(); } private: ConfigureCar* configureCar; // 维持一个对抽象构件对象的引用 }; // ConcreteDecorator(具体装饰类),作用是给基础类装饰新功能 // addLaserHeadLights , add8Turbo , changeSnowtires , class addLaserHeadLights : public Decorator { public: explicit addLaserHeadLights(ConfigureCar* configureCar) : Decorator(configureCar) { std::cout << "开始改装激光大灯" << std::endl; }; ~addLaserHeadLights() override { std::cout << "改装激光大灯结束" << std::endl; } std::string ConfigureTheCar() override { return Decorator::ConfigureTheCar() + ",改装了激光大灯"; } float CalculatePrice() override { return Decorator::CalculatePrice() + float(20); } }; class add8Turbo : public Decorator { public: explicit add8Turbo(ConfigureCar* configureCar) : Decorator(configureCar) { std::cout << "开始改装8涡轮增压" << std::endl; }; ~add8Turbo() override { std::cout << "改装8涡轮增压结束" << std::endl; } std::string ConfigureTheCar() override { return Decorator::ConfigureTheCar() + ",改装了8涡轮增压"; } float CalculatePrice() override { return Decorator::CalculatePrice() + 30; } }; class changeSnowtires : public Decorator { public: explicit changeSnowtires(ConfigureCar* configureCar) : Decorator(configureCar) { std::cout << "开始换雪地胎" << std::endl; }; ~changeSnowtires() override { std::cout << "换雪地胎结束" << std::endl; } std::string ConfigureTheCar() override { return Decorator::ConfigureTheCar() + ",换了雪地胎"; } float CalculatePrice() override { return Decorator::CalculatePrice() + float(10); } }; // Customer // Customer 购买者 class Customer { public: explicit Customer(const std::string& name) { this->name = name; std::cout << "购买者 " << name << " 来了" << std::endl; } ~Customer() { delete configureCar; std::cout << "购买者 " << name << " 走了" << std::endl; } void buy(ConfigureCar* pancake) { this->configureCar = pancake; std::cout << name + "喜提:" << pancake->ConfigureTheCar() << ",共花了:" << std::setiosflags(std::ios::fixed) << std::setprecision(2) << pancake->CalculatePrice() << "万元钱" << std::endl; } private: std::string name; ConfigureCar* configureCar = nullptr; }; // 测试 int main() { std::cout << "网站:https://www.codecomeon.com/" << std::endl; std::cout << std::endl; auto* customerA = new Customer("马云"); customerA->buy(new ConcreteConfigureCar(Base150)); delete customerA; std::cout << "================" << std::endl; auto* customerB = new Customer("马化腾"); customerB->buy(new addLaserHeadLights(new ConcreteConfigureCar(Base200))); delete customerB; std::cout << "================" << std::endl; auto* customerC = new Customer("王健林"); customerC->buy(new changeSnowtires(new add8Turbo(new addLaserHeadLights(new ConcreteConfigureCar(Base200))))); delete customerC; std::cout << "================" << std::endl; return 0; } #### 执行输出 [![装饰器模式](http://www.codecomeon.com:80/group1/M00/00/00/rBlbH2IXeXiAQRFNAADzW963tFk6481288 "装饰器模式")](http://www.codecomeon.com:80/group1/M00/00/00/rBlbH2IXeXiAQRFNAADzW963tFk6481288 "装饰器模式") 综上所述,还是王健林稍微豪横。 本文标题: C++设计模式-装饰器模式 本文作者: 夏至未至 发布时间: 2021年10月23日 23:01 最近更新: 2022年2月24日 20:31 原文链接: 许可协议: 署名-非商业性-禁止演绎 4.0 国际(CC BY-NC-ND 4.0) 请按协议转载并保留原文链接及作者 设计模式(25) 装饰器模式(1) 上一个 C++设计模式-外观模式 下一个 C++设计模式-组合模式 当前文章评论暂未开放,请移步至留言处留言。