Decorator装饰者【C++实现】

Decorator装饰者

一、简介

​ 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变对象的结构。装饰者设计模式属于结构型模式,它是作为现有类的一个包装。

二、应用场景

​ 当一个类设计好后,其功能往往已达到一个相对平衡的状态。此后,如果想要拓展功能,装饰者比继承更有弹性。

所以说,可以考虑在扩展类功能时使用装饰者模式。

​ 很多时候,在类的功能定义上会出现与类实际的预期扩展功能在设计上出现不匹配的情况,这时候使用“组合”还比较合理,此种场景下也可以选择使用装饰者模式。

三、优缺点
(3-1)优点

​ 1、对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。

​ 2、可以通过一种动态的方式来扩展一个对象的功能。

​ 3、可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合进行多次装饰。

​ 4、具体构件类与具体装饰类可以独立变化,符合“开闭原则”。

(3-2)缺点

​ 1、装饰模式中会增加很多小的对象,对象的区别主要在于各种装饰的组合方式不同,而并不是职责不同,大量小对象的产生会占用较多的系统资源。

​ 2、装饰模式比继承更灵活【可随意组合】,但也更容易出错,因此更难于排错。

四、Decorator装饰者模式结构
(4-1)设计核心

​ 装饰者模式的核心设计思想:抽象装饰类的设计,抽象装饰类(装饰器类)和原始类继承同样的父类,这样可以对原始类“嵌套”多个装饰器类。抽象装饰类(装饰器类)是对功能的增强,这也是装饰器模式应用场景的一个重要特点。并且抽象装饰类维持一个对抽象构件对象的引用component抽象装饰类可以通过构造函数或Setter方法注入一个抽象构件类型的对象

​ 总之,装饰的目的就是为了拓展已有类的功能。

(4-2)结构描述

​ 1、Component(抽象组件类):是具体组件类和抽象装饰类的共同父类。

​ 2、ConcreteComponent(具体构件):是抽象构件类的子类,实现了在抽象构件中声明的方法,装饰器就是为它增加额外的功能(方法)。

​ 3、Decorator(抽象装饰类): 它也是抽象构件类的子类,用于给具体构件增加功能,但是具体功能在它的子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用构件对象的方法,并通过其子类(具体装饰类)扩展该方法,以达到装饰的目的。

​ 4、ConcreteDecorator(具体装饰类): 它是抽象装饰类的子类,负责向构件添加新的功能。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充类的行为。

(4-3)类图

在这里插入图片描述

五、【C++】代码实现

​ 小生平时还是算比较爱做饭吧,于是场景来了:一天,家里小聚,某弟娃想吃酸菜鱼,某小妹想吃麻辣鱼,某大姨想吃豆腐酸菜鱼…。

​ ​ 于是乎,陷入沉思,三个人都要吃鱼,而且是三种味道不同的鱼,进一步分析,发现主要是其配料不同(酸菜、豆腐、小米辣),使用相同的鱼。故而使用装饰者模式来设计:

  • 【酸菜鱼】 = 酸菜 + 鱼

  • 【麻辣鱼】 = 小米辣 + 鱼

  • 【豆腐酸菜鱼】 = 豆腐 + 酸菜 + 鱼

(5-1)Component(抽象组件)

​ 本应用场景下的具体组件是:Fish

class Fish {
public:
    virtual  ~Fish() = default;
    //烹饪
    virtual  std::string cooking() = 0;

protected:
    Fish() = default;
};
(5-2)ConcreteComponent(具体组件)

​ 本应用场景下的具体组件是:ConcreteFish

//具体构件
class ConcreteFish :public Fish{
public:
    explicit ConcreteFish(){}
    ~ConcreteFish() override{}

    std::string cooking() override
    {
        return name;
    }

private:
    std::string name = "fish";
};
(5-3)Decorator(抽象装饰类)

​ 本应用场景中的抽象装饰类是:CondimentDecorator

//抽象装饰类
class  CondimentDecorator : public Fish{
public:
    explicit CondimentDecorator(Fish *fish){
        this->m_fish = fish;
    }

    std::string cooking()override{
        return m_fish->cooking();
    }

    ~CondimentDecorator()override{
        if(m_fish)
            delete m_fish;
    }

private:
    //维持一个对抽象构件的引用
    Fish *m_fish;
};
(5-4)ConcreteDecorator(具体装饰组件)

​ 具体装饰组件有:Sauerkraut(酸菜)、Spicy(小米辣)、Doufu(豆腐)

//具体装饰类:
//1、酸菜
//2、小米辣
//3、豆腐

//酸菜
class Sauerkraut :public CondimentDecorator{
public:
    explicit Sauerkraut(Fish *fish):CondimentDecorator(fish)
    {
        std::cout<<"Sauerkraut"<<std::endl;
    }

    std::string cooking()override{
        return "[Sauerkraut]"+ CondimentDecorator::cooking();
    }
};

//小米辣
class Spicy :public CondimentDecorator{
public:
    explicit Spicy(Fish *fish):CondimentDecorator(fish)
    {
        std::cout<<"Spicy"<<std::endl;
    }

    std::string cooking()override{
        return "[Spicy]"+ CondimentDecorator::cooking() ;
    }
};

//豆腐
class Doufu :public CondimentDecorator{
public:
    explicit Doufu(Fish *fish):CondimentDecorator(fish)
    {
        std::cout<<"Doufu"<<std::endl;
    }

    std::string cooking()override{
        return "[Doufu]"+ CondimentDecorator::cooking();
    }
};
六、测试

​ 创建一个People类,其行为有eat吃行为。如下代码片段:

class People {
public:
    explicit People(const std::string& name)
    {
        this->m_name = name;
        std::cout<<"people name: " << m_name <<std::endl;
    }

    //吃
    void eat(Fish *fish)
    {
        this->m_fish = fish;

        std::cout<<"eat:"<<m_fish->cooking()<<std::endl;
    }

private:
    std::string m_name;
    Fish *m_fish = nullptr;
};
(6-1)main函数
//main.h

#include <iostream>

#include "People.h"
#include "CondimentDecorator.h"

int main() {
    std::cout << "Decortor Demo" << std::endl;

    std::cout<<"=============================================\r\n";
    //弟娃想吃酸菜鱼 【鱼 + 酸菜】
    auto *brother = new People("brother");
    brother->eat(new Sauerkraut(new ConcreteFish));
    delete  brother;

    std::cout<<"=============================================\r\n";

    //小妹想吃麻辣鱼【鱼 + 小米辣】
    auto *sister = new People("sister");
    sister->eat(new Spicy(new ConcreteFish));
    delete sister;

    std::cout<<"=============================================\r\n";

    //大姨想吃豆腐酸菜鱼【鱼 + 豆腐 + 酸菜】
    auto *aunt = new People("aunt");
    aunt->eat(new Sauerkraut(new Doufu(new ConcreteFish)));
    delete aunt;

    return 0;
}
(6-2)运行结果

在这里插入图片描述


站在巨人的肩膀上

【1】https://blog.csdn.net/leacock1991/article/details/112056643

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值