1、定义
动态地给一个对象增加一些额外的职责。就增加功能而言,装饰器模式比生产子类更为灵活。—— 《设计模式》GoF
2、代码实现
代码背景:普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能针对不同的职位产生不同的奖金组合;
#include <iostream>
using namespace std;
//封装被计算奖金的人员信息
class Context {
public:
bool isMgr;
// User user;
// double groupsale;
};
// 试着从职责出发,将职责抽象出来
class CalcBonus {
public:
CalcBonus(CalcBonus * c = nullptr) : cc(c) {}
virtual double Calc(Context &ctx) {
return 0.0; // 基本工资
}
virtual ~CalcBonus() {}
protected:
CalcBonus* cc;
};
//月度奖金
class CalcMonthBonus : public CalcBonus {
public:
CalcMonthBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double mbonus /*= 计算流程忽略*/;
return mbonus + cc->Calc(ctx);
}
};
//季度奖金
class CalcSumBonus : public CalcBonus {
public:
CalcSumBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double sbonus /*= 计算流程忽略*/;
return sbonus + cc->Calc(ctx);
}
};
//小组奖金
class CalcGroupBonus : public CalcBonus {
public:
CalcGroupBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
//环比奖金
class CalcCycleBonus : public CalcBonus {
public:
CalcCycleBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
int main() {
// 1. 普通员工
Context ctx1;
//就是在每个奖金的基础上进行叠加(叠加没有先后顺序)
CalcBonus *base = new CalcBonus();
CalcBonus *cb1 = new CalcSumBonus(base);
CalcBonus *cb2 = new CalcMonthBonus(cb1);
cb2->Calc(ctx1);
// 2. 部门经理
Context ctx2;
CalcBonus *cb3 = new CalcGroupBonus(cb2);
cb3->Calc(ctx2);
}
代码分析:
-
实现起来和责任链有点相似,装饰者模式就像一层套一层的感觉,不需要有顺序,只要该套的套完了就行
-
责任链:强调顺序,且可以在某个位置打断
-
装饰者:强调结果,顺序无所谓
-
-
责任链是第一环调用处理函数,这里是装饰的最后一个调用处理函数
3、要点
-
装饰者模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能
-
装饰者模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,实现复用装饰器的功能
-
场景:给一个主体叠加多层需求的场景
- 给某个员工计算奖金
- 给游戏人物搭配衣服
- 给一辆汽车选配置
- …
4、本质
- 动态组合—对一个对象进行多重自定义装饰,不考虑顺序,只考虑装饰结果