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

设计模式介绍

一、装饰模式

1. 装饰模式定义

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。

2. 装饰模式本质

动态组合

3. 装饰模式结构和说明

(1) 结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2) 调用顺序

以示例代码为例:
在这里插入图片描述

4. 装饰模式适用情况

  1. 如果需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责,可以使用装饰模式,这几乎就是装饰模式的主要功能。
  2. 如果不适合使用子类来进行扩展的时候,可以考虑使用装饰模式。因为装饰模式是使用的“对象组合”的方式。所谓不适合用子类扩展的方式,比如,扩展功能需要的子类太多,造成子类数目呈爆炸性增长。

5. 装饰模式优缺点

(1) 优点

1.比继承更灵活
从为对象添加功能的角度来看,装饰模式比继承更灵活。继承是静态的,而且一旦继承所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器当中,然后通过对象组合的方式,在运行时动态地组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能来决定的。
2.更容易复用功能
装饰模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,使实现装饰器变得简单,更重要的是这样有利于装饰器功能的复用,可以给一个对象增加多个同样的装饰器,也可以把一个装饰器用来装饰不同的对象,从而实现复用装饰器的功能。
3.简化高层定义
装饰模式可以通过组合装饰器的方式,为对象增添任意多的功能。因此在进行高层定义的时候,不用把所有的功能都定义出来,而是定义最基本的就可以了,可以在需要使用的时候,组合相应的装饰器来完成所需的功能。

(2) 缺点

1.会产生很多细粒度对象。
前面说了,装饰模式是把一系列复杂的功能,分散到每个装饰器当中,一般一个装饰器只实现一个功能,这样会产生很多细粒度的对象,而且功能越复杂,需要的细粒度对象越多。

6. 相关模式

  1. 装饰模式与适配器模式
    这是两个没有什么关联的模式,放到一起来说,是因为它们有一个共同的别名:Wrappere
    这两个模式功能上是不一样的,适配器模式是用来改变接口的,而装饰模式是用来改变对象功能的。
  2. 装饰模式与组合模式
    这两个模式有相似之处,都涉及到对象的递归调用,从某个角度来说,可以把装饰看做是只有一个组件的组合。
    但是它们的目的完全不一样,装饰模式是要动态地给对象增加功能:而组合模式是想要管理组合对象和叶子对象,为它们提供一个一致的操作接口给客户端,方便客户端的使用。
  3. 装饰模式与策略模式
    这两个模式可以组合使用。
    策略模式也可以实现动态地改变对象的功能,但是策略模式只是一层选择,也就是根据策略选择一下具体的实现类而已。而装饰模式不是一层,而是递归调用,无数层都可以,只要组合好装饰器的对象组合,那就可以依次调用下去。所以装饰模式更灵活。
    而且策略模式改变的是原始对象的功能,不像装饰模式,后面一个装饰器,改变的是经过前一个装饰器装饰后的对象。也就是策略模式改变的是对象的内核,而装饰模式改变的是对象的外壳。
    这两个模式可以组合使用,可以在一个具体的装饰器中使用策略模式来选择更具体的实现方式。
  4. 装饰模式与模板方法模式
    这是两个功能上有相似点的模式。
    模板方法模式主要应用在算法骨架固定的情况,那么要是算法步骤不固定呢,也就是一个相对动态的算法步骤,就可以使用装饰模式了,因为在使用装饰模式的时候,进行装饰器的组装,其实也相当于是一个调用算法步骤的组装,相当于是一个动态的算法骨架。
    既然装饰模式可以实现动态的算法步骤的组装和调用,那么把这些算法步骤固定下来,那就是模板方法模式实现的功能了,因此装饰模式可以模拟实现模板方法模式的功能。

装饰模式示例代码

#include <iostream>
#include <string>
#include <memory>

using namespace std;

//高层组件
class Component
{
public:
    //计算奖金
    virtual uint32_t CalcPrize(std::string user){return 0;}
};

//计算奖金组件
class ConcreteComponent : public Component
{
public:
    //基础计算奖金
    uint32_t CalcPrize(std::string user) override
    {
        return 0;//默认返回0
    };
};

//抽象装饰器
class Decorator : public Component
{
public:
    uint32_t CalcPrize(std::string user){return 0;}
};

//各种装饰器
//团队计算奖金
class GroupPrizeDecorator : public Decorator
{
public:
    GroupPrizeDecorator(){}
    GroupPrizeDecorator(Decorator* pDecorator) : pComponent (pDecorator){}
public:
    //计算团队奖金
    uint32_t CalcPrize(std::string user) override
    {
        uint32_t prize = 0;
        uint32_t groupPrize = 1000;
        if(pComponent != nullptr)
        {
            prize = pComponent->CalcPrize(user);
        }

        if(user == "张三")
        {
            prize += groupPrize;
            std::cout<<user<<":团队奖金为:1000元"<<std::endl;
        }
        return prize;
    }

private:
    std::unique_ptr<Decorator> pComponent;
};

//个人累计奖金
class SumPrizeDecorator : public Decorator
{
public:
    SumPrizeDecorator(){}
    SumPrizeDecorator(Decorator* pDecorator) : pComponent (pDecorator){}
public:
    //个人累计奖金
    uint32_t CalcPrize(std::string user) override
    {
        uint32_t prize = 500;
        if(pComponent != nullptr)
        {
            prize += pComponent->CalcPrize(user);
        }
        std::cout<<user<<":累计奖金为:500元"<<std::endl;
        return prize;
    }

private:
    std::unique_ptr<Decorator> pComponent;
};

//个人月度奖金
class MonthPrizeDecorator : public Decorator
{
public:
    MonthPrizeDecorator(){}
    MonthPrizeDecorator(Decorator* pDecorator) : pComponent (pDecorator){}
public:
    //计算个人月度奖金
    uint32_t CalcPrize(std::string user) override
    {
        uint32_t prize = 200;
        if(pComponent != nullptr)
        {
            prize += pComponent->CalcPrize(user);
        }
        std::cout<<user<<":月度奖金为:200元"<<std::endl;
        return prize;
    }

private:
    std::unique_ptr<Decorator> pComponent;
};

int main()
{
    //张三为项目经理 只有张三才有团队奖金
    {
        //计算个人奖金
        Component* pComponent = new GroupPrizeDecorator(new SumPrizeDecorator(new MonthPrizeDecorator()));
        uint32_t prize = pComponent->CalcPrize("张三");
        std::cout<<"张三:总奖金为:"<<prize<<std::endl;
        prize = pComponent->CalcPrize("李四");
        std::cout<<"李四:总奖金为:"<<prize<<std::endl;
    }


    std::cout<<"------------------调换一下装饰器顺序------------------------"<<std::endl;

    {
        Component* pComponent = new SumPrizeDecorator(new MonthPrizeDecorator(new GroupPrizeDecorator()));
        uint32_t prize = pComponent->CalcPrize("张三");
        std::cout<<"张三:总奖金为:"<<prize<<std::endl;
        prize = pComponent->CalcPrize("李四");
        std::cout<<"李四:总奖金为:"<<prize<<std::endl;
    }

    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值