设计模式介绍
一、装饰模式
1. 装饰模式定义
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。
2. 装饰模式本质
动态组合
3. 装饰模式结构和说明
(1) 结构
(2) 调用顺序
以示例代码为例:
4. 装饰模式适用情况
- 如果需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责,可以使用装饰模式,这几乎就是装饰模式的主要功能。
- 如果不适合使用子类来进行扩展的时候,可以考虑使用装饰模式。因为装饰模式是使用的“对象组合”的方式。所谓不适合用子类扩展的方式,比如,扩展功能需要的子类太多,造成子类数目呈爆炸性增长。
5. 装饰模式优缺点
(1) 优点
1.比继承更灵活
从为对象添加功能的角度来看,装饰模式比继承更灵活。继承是静态的,而且一旦继承所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器当中,然后通过对象组合的方式,在运行时动态地组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能来决定的。
2.更容易复用功能
装饰模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,使实现装饰器变得简单,更重要的是这样有利于装饰器功能的复用,可以给一个对象增加多个同样的装饰器,也可以把一个装饰器用来装饰不同的对象,从而实现复用装饰器的功能。
3.简化高层定义
装饰模式可以通过组合装饰器的方式,为对象增添任意多的功能。因此在进行高层定义的时候,不用把所有的功能都定义出来,而是定义最基本的就可以了,可以在需要使用的时候,组合相应的装饰器来完成所需的功能。
(2) 缺点
1.会产生很多细粒度对象。
前面说了,装饰模式是把一系列复杂的功能,分散到每个装饰器当中,一般一个装饰器只实现一个功能,这样会产生很多细粒度的对象,而且功能越复杂,需要的细粒度对象越多。
6. 相关模式
- 装饰模式与适配器模式
这是两个没有什么关联的模式,放到一起来说,是因为它们有一个共同的别名:Wrappere
这两个模式功能上是不一样的,适配器模式是用来改变接口的,而装饰模式是用来改变对象功能的。 - 装饰模式与组合模式
这两个模式有相似之处,都涉及到对象的递归调用,从某个角度来说,可以把装饰看做是只有一个组件的组合。
但是它们的目的完全不一样,装饰模式是要动态地给对象增加功能:而组合模式是想要管理组合对象和叶子对象,为它们提供一个一致的操作接口给客户端,方便客户端的使用。 - 装饰模式与策略模式
这两个模式可以组合使用。
策略模式也可以实现动态地改变对象的功能,但是策略模式只是一层选择,也就是根据策略选择一下具体的实现类而已。而装饰模式不是一层,而是递归调用,无数层都可以,只要组合好装饰器的对象组合,那就可以依次调用下去。所以装饰模式更灵活。
而且策略模式改变的是原始对象的功能,不像装饰模式,后面一个装饰器,改变的是经过前一个装饰器装饰后的对象。也就是策略模式改变的是对象的内核,而装饰模式改变的是对象的外壳。
这两个模式可以组合使用,可以在一个具体的装饰器中使用策略模式来选择更具体的实现方式。 - 装饰模式与模板方法模式
这是两个功能上有相似点的模式。
模板方法模式主要应用在算法骨架固定的情况,那么要是算法步骤不固定呢,也就是一个相对动态的算法步骤,就可以使用装饰模式了,因为在使用装饰模式的时候,进行装饰器的组装,其实也相当于是一个调用算法步骤的组装,相当于是一个动态的算法骨架。
既然装饰模式可以实现动态的算法步骤的组装和调用,那么把这些算法步骤固定下来,那就是模板方法模式实现的功能了,因此装饰模式可以模拟实现模板方法模式的功能。
装饰模式示例代码
#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;
}