装饰模式的结构和说明
①Component:组件对象的接口,可以给这些对象动态地添加职责。
②ConcreteComponent:具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。
③Decorator:所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象的指针,其实就是持有一个被装饰的对象。之所以从Decorator继承而来,除了与被装饰对象接口相同,还是有个原因是Decorator本身也可以被进一步的装饰,形成多层的装饰。注意,装饰后仍然是一个Component对象,而且其功能更为复杂。
④ConcreteDecorator:实际的装饰器对象,实现具体要向被装饰对象添加的功能。
思考装饰模式
①装饰模式的本质:动态组合。动态是手段,组合才是目的。通过对象组合(而不是继承)来实现为被装饰对象透明的增加功能,而且也可以控制功能的访问。
②装饰模式的动机:由于继承为类型引入的静态特质,使得通过继承扩展方式缺乏灵活性,并且随着子类的增多,会导致子类的膨胀。而装饰模式可以根据需要来动态地使“对象功能扩展”,避免子类膨胀问题。
③装饰器:不仅仅可以给被装饰对象增加功能,还可以根据需要选择是否调用被装饰对象的功能。如果不调用,那就变成完全重新实现,相当于动态修改了被装饰对象的功能。同时装饰器一定要实现和组件类一致的接口,保证它们是同一个类型,并具有同一个外观,这样组合完成的装饰才能够递归调用下去。
【编程实验】奖金的计算
//声明文件
//结构型模式:装饰模式 //场景:计算奖金的方法。 //奖金的计算方式: //1.奖金分为个人奖金和业务主管(经理)两种不同的计算方式等。 //2.个人奖金大致有个人当月业务奖金、个人累计奖金、个人业务增长奖金、及时回款奖金 // 限时成交加码奖等。对于业务主管除了个人奖金外,还有团队累计奖金和团队业务增长 // 奖金、团队盈利奖等。 //简化后的奖金计算体系 //1.每个人当月业务奖金 = 当月销售额* 3% //2.每个人累计奖金 = 总的回款额* 0.1% //3.团队奖金 = 团队总销售额* 1% #include <iostream> #include <map> #include <string> using namespace std; //********************辅助类********************************* //在内存中模拟数据库,准备测试数据,好计算奖金 class CTmpDB{ private: CTmpDB(){} public: //记录每个人的月度销售额,只用了人员,月份没有用 static map<string, double> mpSalary; }; //************************抽象组件类****************** //计算奖金的组件接口 class CMoney{ public: virtual ~CMoney(); virtual double MakeLiving(string user) = 0; }; //基本的实现计算奖金的类,也是被装饰器装饰的对象 class CBasePay : public CMoney{ public: ~CBasePay(); double MakeLiving(string user); }; //************************定义抽象的装饰器********************** class CMoneyDecorator : public CMoney{ protected: CMoney* pBase; public: CMoneyDecorator(CMoney* base); ~CMoneyDecorator(); double MakeLiving(string user); }; //定义一系列的装饰器对象 //装饰器对象:计算当月业务奖金 class CMonthPrize : public CMoneyDecorator{ public: CMonthPrize(CMoney* base); ~CMonthPrize(); double MakeLiving(string user); }; //装饰器对象:计算累计奖金 class CSumPrize : public CMoneyDecorator{ public: CSumPrize(CMoney* base); ~CSumPrize(); double MakeLiving(string user); }; //装饰器对象:计算当月团队业务奖金 class CGroupPrize : public CMoneyDecorator{ public: CGroupPrize(CMoney* base); ~CGroupPrize(); double MakeLiving(string user); };
//实现文件
//********************辅助类********************************* //在内存中模拟数据库,准备测试数据,好计算奖金 static map<string, double>::value_type init_value[]= { map<string, double>::value_type("ZhangSan", 10000.0), map<string, double>::value_type("LiSi", 20000.0), map<string, double>::value_type("WangWu", 30000.0) }; map<string, double> CTmpDB::mpSalary(init_value, init_value+3); //************************抽象组件类****************** //计算奖金的组件接口 CMoney::~CMoney(){} //基本的实现计算奖金的类,也是被装饰器装饰的对象 CBasePay::~CBasePay(){ cout << "~基本工资" << endl;} double CBasePay::MakeLiving(string user) { cout << "基本工资:" << CTmpDB::mpSalary[user] << endl << "*************" << endl; return CTmpDB::mpSalary[user]; } //************************定义抽象的装饰器********************** CMoneyDecorator::CMoneyDecorator(CMoney* base) : pBase(base){} double CMoneyDecorator::MakeLiving(string user){ return pBase->MakeLiving(user);} CMoneyDecorator::~CMoneyDecorator(){delete pBase;} //定义一系列的装饰器对象 //装饰器对象:计算当月业务奖金 CMonthPrize::CMonthPrize(CMoney* base) : CMoneyDecorator(base){} CMonthPrize::~CMonthPrize(){cout << "~当月业务奖金" << endl;} double CMonthPrize::MakeLiving(string user) { double dMoney = pBase->MakeLiving(user)*0.03; cout << "当月业务奖金:" << dMoney << endl; return pBase->MakeLiving(user) + dMoney; } //装饰器对象:计算累计奖金 CSumPrize::CSumPrize(CMoney* base) : CMoneyDecorator(base){} CSumPrize::~CSumPrize(){cout << "~累计奖金" << endl;} double CSumPrize::MakeLiving(string user) { cout << "累计奖金:" << 10000*0.02 << endl; return pBase->MakeLiving(user) + 10000*0.02; } //装饰器对象:计算当月团队业务奖金 CGroupPrize::CGroupPrize(CMoney* base) : CMoneyDecorator(base){} CGroupPrize::~CGroupPrize(){cout << "~团队业务奖金" << endl;} double CGroupPrize::MakeLiving(string user) { double dMoney = 0.0; for(map<string, double>::iterator it = CTmpDB::mpSalary.begin(); it != CTmpDB::mpSalary.end(); it++){ dMoney += it->second; } cout << "团队业务奖金:" << dMoney*0.01 << endl; return pBase->MakeLiving(user) + dMoney*0.01; }
//测试客户端
void main() { CMoney* pBase = new CBasePay(); CMoney* pMonthPrize = new CMonthPrize(pBase); CMoney* pSumPrize = new CSumPrize(pMonthPrize); CGroupPrize* pGroupPrize = new CGroupPrize(pSumPrize); cout << "ZhangSan : " << pGroupPrize->MakeLiving("ZhangSan") << endl; delete pGroupPrize; }