合肥市重点工程建设管理局网站,长春哪家网站做的好,wordpress paypal支付,建设企业网站怎样收费设计模式是我们软件架构开发中不可缺失的一部分#xff0c;通过学习设计模式#xff0c;我们可以更好理解的代码的结构和层次。
设计原则
设计原则是早于设计方法出现的#xff0c;所以的设计原则都要依赖于设计方法。这里主要有八个设计原则。 推荐一个零声学院免费教程通过学习设计模式我们可以更好理解的代码的结构和层次。
设计原则
设计原则是早于设计方法出现的所以的设计原则都要依赖于设计方法。这里主要有八个设计原则。 推荐一个零声学院免费教程个人觉得老师讲得不错分享给大家[LinuxNginxZeroMQMySQLRedis fastdfsMongoDBZK流媒体CDNP2PK8SDocker TCP/IP协程DPDK等技术内容点击立即学习:链接 依赖倒置 高层模块不应该依赖低层模块两者都应该依赖抽象抽象不应该依赖具体实现具体实现应该依赖于抽象 这个怎么理解呢 第一点是上层的模块例如直接给用户使用的API 不能直接暴露底层的实现给用户 要通过中间的一层抽象接口。 例如: 自动驾驶系统公司是高层汽车生产厂商为低层它们不应该互相依赖一方变动另一方也会跟着变动而应该抽象一个自动驾驶行业标准高层和低层都依赖它这样以来就解耦了两方的变动自动驾驶系统、汽车生产厂商都是具体实现它们应该都依赖自动驾驶行业标准抽象 开放封闭 一个类应该对扩展组合和继承开放对修改关闭 类中的接口应该对需要组合/继承的类暴露接口对需要常变的封装到private里面。 面向接口 不将变量类型声明为某个特定的具体类而是声明为某个接口客户程序无需获知对象的具体类型只需要知道对象所具有的接口减少系统中各部分的依赖关系从而实现“高内聚、松耦合”的类型设计方案 封装变化点 将稳定点和变化点分离扩展修改变化点让稳定点和变化点的实现层次分离 单一职责 一个类应该仅有一个引起它变化的原因 里氏替换 子类型必须能够替换掉它的父类型主要出现在子类覆盖父类实现原来使用父类型的程序可能出现错误覆盖了父类方法却没有实现父类方法的职责 接口隔离 不应该强迫客户依赖于它们不用的方法一般用于处理一个类拥有比较多的接口而这些接口涉及到很多职责;客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上 组合优于继承 继承耦合度高组合耦合度低
1. 模板方法
定义定义一个操作中的算法的骨架 而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
要点
最常用的设计模式子类可以复写父类子流程使父类的骨架流程丰富反向控制流程的典型应用父类 protected 保护子类需要复写的子流程这样子类的子流程只能父类来调用
结构图 我们可以看到父类是一个抽象类父类的接口由子类来复写实现。 我们先来看下没有用模板方法写的代码。 我们顶一个了类zoo里面的实现由show0, show1, show2… 如果想添加一个新的show的则需要在类zoo里面添加这样就破坏了 类zoo的封装 加入类zoo我们不想暴露给用户去修改呢
#include iostream
using namespace std;
class ZooShow {
public:ZooShow(int type 1) : _type(type) {}public:void Show() {if (Show0())PlayGame();Show1();Show2();Show3();}private:void PlayGame() {cout after Show0, then play game endl;}bool Show0() {if (_type 1) {// return true;} else if (_type 2 ) {// ...} else if (_type 3) {}cout _type show0 endl;return true;}void Show1() {if (_type 1) {cout _type Show1 endl;} else if (_type 2) {cout _type Show1 endl;} else if (_type 3) {}}void Show2() {if (_type 20) {}cout base Show2 endl;}void Show3() {if (_type 1) {cout _type Show1 endl;} else if (_type 2) {cout _type Show1 endl;}}
private:int _type;
};int main () {ZooShow *zs new ZooShow(1);bzs-Show();return 0;
}使用模板方法 我们把父类的接口固定然后定义若干个子类去继承父类的接口。在使用时只需定义父类的指针指向要实现的子类的对象即可。
#include iostream
using namespace std;
// 开闭
class ZooShow {
public:void Show() {// 如果子表演流程没有超时的话进行一个中场游戏环节如果超时直接进入下一个子表演流程if (Show0())PlayGame();Show1();Show2();Show3();}private:void PlayGame() {cout after Show0, then play game endl;}bool expired;// 对其他用户关闭但是子类开放的
protected:virtual bool Show0() {cout show0 endl;if (! expired) {return true;}return false;}virtual void Show2() {cout show2 endl;}virtual void Show1() {}virtual void Show3() {}
};// 框架
// 模板方法模式
class ZooShowEx10 : public ZooShow {
protected:virtual void Show0() {if (! expired) {return true;}return false;}
}class ZooShowEx1 : public ZooShow {
protected:virtual bool Show0() {cout ZooShowEx1 show0 endl;if (! expired) { // 里氏替换return true;}return false;}virtual void Show2(){cout show3 endl;}
};class ZooShowEx2 : public ZooShow {
protected:virtual void Show1(){cout show1 endl;}virtual void Show2(){cout show3 endl;}
};class ZooShowEx3 : public ZooShow {
protected:virtual void Show1(){cout show1 endl;}virtual void Show3(){cout show3 endl;}virtual void Show4() {//}
};
/*
*/
int main () {ZooShow *zs new ZooShowEx10; // 晚绑定// ZooShow *zs1 new ZooShowEx1;// ZooShow *zs2 new ZooShowEx2;zs-Show();return 0;
}2. 观察者模式
定义: 定义对象间的一种一对多变化的依赖关系以便当一个对象(Subject)的状态发生改变时所有依赖于它的对象都得到通知并自动更新。
要点:
观察者模式使得我们可以独立地改变目标与观察者从而使二者之间的关系松耦合;观察者自己决定是否订阅通知目标对象并不关注谁订阅了;观察者不要依赖通知顺序目标对象也不知道通知顺序;常用在基于事件的ui框架中也是 MVC 的组成部分常用在分布式系统中、actor框架中
结构图 首先我们有一个抽象的父类然后几个具体实现的子类 一旦我们observer由任何的变化我们就需要对每个子类的进行通知。
没有使用观察者模式
可以看到我们定义n多个子类去接收CalcTemperature的改变。
class DisplayA {
public:void Show(float temperature);
};class DisplayB {
public:void Show(float temperature);
};class DisplayC {
public:void Show(float temperature);
}class WeatherData {
};class DataCenter {
public:void TempNotify() {DisplayA *da new DisplayA;DisplayB *db new DisplayB;DisplayC *dc new DisplayC;// DisplayD *dd new DisplayD;float temper this-CalcTemperature();da-Show(temper);db-Show(temper);dc-Show(temper);dc-Show(temper);}
private:float CalcTemperature() {WeatherData * data GetWeatherData();// ...float temper/* */;return temper;}WeatherData * GetWeatherData(); // 不同的方式
};int main() {DataCenter *center new DataCenter;center-TempNotify();return 0;
}观察者模式
#include list
#include algorithm
using namespace std;
//
class IDisplay {
public:virtual void Show(float temperature) 0;virtual ~IDisplay() {}
};class DisplayA : public IDisplay {
public:virtual void Show(float temperature) {cout DisplayA Show endl;}
private:void jianyi();
};class DisplayB : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayB Show endl;}
};class DisplayC : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayC Show endl;}
};class DisplayD : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayC Show endl;}
};class WeatherData {
};// 应对稳定点抽象
// 应对变化点扩展继承和组合
class DataCenter {
public:void Attach(IDisplay * ob) {//}void Detach(IDisplay * ob) {//}void Notify() {float temper CalcTemperature();for (auto iter : obs) {iter.Show(temper);}}// 接口隔离
private:WeatherData * GetWeatherData();float CalcTemperature() {WeatherData * data GetWeatherData();// ...float temper/* */;return temper;}std::listIDisplay* obs;
};int main() {// 单例模式DataCenter *center new DataCenter;// ... 某个模块IDisplay *da new DisplayA();center-Attach(da);// ...IDisplay *db new DisplayB();center-Attach(db);IDisplay *dc new DisplayC();center-Attach(dc);center-Notify();//-----center-Detach(db);center-Notify();//....center-Attach(dd);center-Notify();return 0;
}3. 策略模式
定义: 定义一系列算法把它们一个个封装起来并且使它们可互相替换。该模式使得算法可独立于使用它的客户程序而变化。
要点:
策略模式提供了一系列可重用的算法从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换策略模式消除了条件判断语句也就是在解耦合
结构图: 策略模式的本质是用来消除多余的if else的。 没有使用策略模式 enum VacationEnum {VAC_Spring,VAC_QiXi,VAC_Wuyi,VAC_GuoQing,VAC_ShengDan,
};class Promotion {VacationEnum vac;
public:double CalcPromotion(){if (vac VAC_Spring {// 春节}else if (vac VAC_QiXi) {// 七夕}else if (vac VAC_Wuyi) {// 五一}else if (vac VAC_GuoQing) {// 国庆}else if (vac VAC_ShengDan) {}}};使用策略模式
class Context {};// 稳定点抽象去解决它
// 变化点扩展继承和组合去解决它
class ProStategy {
public:virtual double CalcPro(const Context ctx) 0;virtual ~ProStategy();
};
// cpp
class VAC_Spring : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};
// cpp
class VAC_QiXi : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};
class VAC_QiXi1 : public VAC_QiXi {
public:virtual double CalcPro(const Context ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};class VAC_Shengdan : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};class Promotion {
public:Promotion(ProStategy *sss) : s(sss){}~Promotion(){}double CalcPromotion(const Context ctx){return s-CalcPro(ctx);}
private:ProStategy *s;
};int main () {Context ctx;ProStategy *s new VAC_QiXi1();Promotion *p new Promotion(s);p-CalcPromotion(ctx);return 0;
}4. 工厂模式
定义: 定义一个用于创建对象的接口让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。
主要是为了创建同类对象的接口 同类对象只有一个相同的职责。
看一个例子, 没有用工厂模式, 我们需要使用大量的if, else 来判断什么类型的时间。 #include string
// 实现导出数据的接口, 导出数据的格式包含 xmljson文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string data) 0;virtual ~IExport(){}
};class ExportXml : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportJson : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};
// csv
class ExportTxt : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};
int main() {std::string choose/* */;if (choose txt) {/***/IExport *e new ExportTxt();/***/e-Export(hello world);} else if (choose json) {/***/IExport *e new ExportJson();/***/e-Export(hello world);} else if (choose xml) {IExport *e new ExportXml();e-Export(hello world);} else if (choose csv) {IExport *e new ExportXml();e-Export(hello world);}
}
使用工厂模式用IExportFactory把接口创建出来 真正实现延迟到子类实现。
#include string
// 实现导出数据的接口, 导出数据的格式包含 xmljson文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string data) 0;virtual ~IExport(){}
};class ExportXml : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportJson : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportTxt : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportCSV : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class IExportFactory {
public:IExportFactory() {_export nullptr;}virtual ~IExportFactory() {if (_export) {delete _export;_export nullptr;}}bool Export(const std::string data) {if (_export nullptr) {_export NewExport();}return _export-Export(data);}
protected:virtual IExport * NewExport(/* ... */) 0;
private:IExport* _export;
};class ExportXmlFactory : public IExportFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportXml();// 可能之后有什么操作return temp;}
};
class ExportJsonFactory : public IExportFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportJson;// 可能之后有什么操作return temp;}
};
class ExportTxtFactory : public IExportFactory {
protected:IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportTxt;// 可能之后有什么操作return temp;}
};class ExportCSVFactory : public IExportFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportCSV;// 可能之后有什么操作return temp;}
};int main () {IExportFactory *factory new ExportCSVFactory();factory-Export(hello world);return 0;
}1 如果为每一个具体的 ConcreteProduct 类的实例化提供一个函数体 那么我们可能不得不在系统中添加了一个方法来处理这个新建的 ConcreteProduct这样 Factory 的接口永远就不肯能封闭 Close。 当然我们可以通过创建一个 Factory 的子类来通过多态实现这一点但是这也是以新建一个类作为代价的。
2在实现中我们可以通过参数化工厂方法即给 FactoryMethod 传递一个参数用以 决定是创建具体哪一个具体的 Product。当 然也可以通过模板化避免 1中的子类创建子类其方法就是将具体 Product 类作为模板参数实现起来也很简单。可以看出 Factory 模式对于对象的创建给予开发人员提供了很好的实现策略但是Factory 模式仅仅局限于一类类就是说 Product 是一类有一个共同的基类如果我们要为不同类的类提供一个对象创建的接口那就要用 AbstractFactory 了。
5. 抽象工厂
定义: 提供一个接口, 让接口负责创建一系列的相关或者相互依赖的对象 无需指定他们具体的类。
主要是为了创建同类对象的接口和工厂模式最主要的区分是同类对象具有很多相同的职责。 #include string
// 实现导出数据的接口, 导出数据的格式包含 xmljson文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string data) 0;virtual ~IExport(){}
};class ExportXml : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportJson : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportTxt : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class ExportCSV : public IExport {
public:virtual bool Export(const std::string data) {return true;}
};class IImport {
public:virtual bool Import(const std::string data) 0;virtual ~IImport(){}
};class ImportXml : public IImport {
public:virtual bool Import(const std::string data) {return true;}
};class ImportJson : public IImport {
public:virtual bool Import(const std::string data) {return true;}
};class ImportTxt : public IImport {
public:virtual bool Import(const std::string data) {return true;}
};class ImportCSV : public IImport {
public:virtual bool Import(const std::string data) {// ....return true;}
};class IDataApiFactory {
public:IDataApiFactory() {_export nullptr;_import nullptr;}virtual ~IDataApiFactory() {if (_export) {delete _export;_export nullptr;}if (_import) {delete _import;_import nullptr;}}bool Export(const std::string data) {if (_export nullptr) {_export NewExport();}return _export-Export(data);}bool Import(const std::string data) {if (_import nullptr) {_import NewImport();}return _import-Import(data);}
protected:virtual IExport * NewExport(/* ... */) 0;virtual IImport * NewImport(/* ... */) 0;
private:IExport *_export;IImport *_import;
};class XmlApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportXml;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作或者许多参数IImport * temp new ImportXml;// 可能之后有什么操作return temp;}
};class JsonApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportJson;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作或者许多参数IImport * temp new ImportJson;// 可能之后有什么操作return temp;}
};
class TxtApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportTxt;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作或者许多参数IImport * temp new ImportTxt;// 可能之后有什么操作return temp;}
};class CSVApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作或者许多参数IExport * temp new ExportCSV;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作或者许多参数IImport * temp new ImportCSV;// 可能之后有什么操作return temp;}
};// 相关性 依赖性 工作当中
int main () {IDataApiFactory *factory new CSVApiFactory();factory-Import(hello world);factory-Export(hello world);return 0;
}AbstractFactory 模式和 Factory 模式的区别是初学使用设计模式时候的一个容易引起困惑的地方。 实际上 AbstractFactory 模式是为创建一组 有多类 相关或依赖的对象提供创建接口 而 Factory 模式正如我在相应的文档中分析的是为一类对象提供创建接口或延 迟对象的创建到子类中实现。并且可以看到 AbstractFactory 模式通常都是使用 Factory 模式实现 ConcreteFactory1。
6. 责任链模式
定义: 使多个对象都有机会处理请求从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链并沿着这条链传递请求直到有一个对象处理它为止。 这个思路很容易理解一条链上有若干个请求每个请求都有可能被每一个节点处理处理完可能就不需要后面的来处理了。 Chain of Responsibility 模式中 ConcreteHandler 将自己的后继对象向下传递消息的对象记录在自己的后继表中当一个请求到来时 ConcreteHandler 会先检查看自己有没有匹配的处理程序 如果有就自己处理 否则传递给它的后继。 当然这里示例程序中为了简化ConcreteHandler 只是简单的检查看自己有没有后继有的话将请求传递给后继进行处理没有的话就自己处理。
#include iostream
using namespace std;
class Handle
{
public:virtual ~Handle();virtual void HandleRequest() 0;void SetSuccessor(Handle* succ) { _succ succ; }Handle* GetSuccessor() { return _succ; }
protected:Handle() { _succ NULL; }Handle(Handle* succ) { this-_succ succ; }
private:Handle* _succ;
};
class ConcreteHandleA:public Handle
{
public:ConcreteHandleA();~ConcreteHandleA();ConcreteHandleA(Handle* succ) : Handle(succ) {}void HandleRequest(){if (this-GetSuccessor() ! 0) {coutConcreteHandleA request to next .....endl;this-GetSuccessor()-HandleRequest();} else {coutConcreteHandleA handleendl;}}
protected:
private:
};class ConcreteHandleB:public Handle
{
public:ConcreteHandleB();~ConcreteHandleB();ConcreteHandleB(Handle* succ):: Handle(succ) {}void HandleRequest() {if (this-GetSuccessor() ! 0) {coutConcreteHandleA request to next .....endl;this-GetSuccessor()-HandleRequest();} else {coutConcreteHandleA handleendl;}}
protected:
private:
};int main() {Handle* h1 new ConcreteHandleA();Handle* h2 new ConcreteHandleB();h1-SetSuccessor(h2);h1-HandleRequest();return 0;
}Chain of Responsibility 模式的示例代码实现很简单这里就其测试结果给出说明ConcreteHandleA 的对象和 h1 拥有一个后继 ConcreteHandleB 的对象 h2,当一个请求到来时候 h1 检查看自己有后继于是 h1 直接将请求传递给其后继 h2 进行处理 h2 因为没有后继当请求到来时候就只有自己提供响应了。
Chain of Responsibility 模式的最大的一个有点就是给系统降低了耦合性 请求的发送者完全不必知道该请求会被哪个应答对象处理极大地降低了系统的耦合性。
7 装饰器模式
在 OO 设计和开发过程 可能会经常遇到以下的情况 我们需要为一个已经定义好的类添加新的职责操作 通常的情况我们会给定义一个新类继承自定义好的类这样会带来一个问题 将在本模式的讨论中给出。通过继承的方式解决这样的情况还带来了系统的复 杂性因为继承的深度会变得很深。而 Decorator 提供了一种给类增加职责的方法不是通过继承实现的而是通过组合。 在 结 构 图 中 ConcreteComponent 和 Decorator 需 要 有 同 样 的 接 口 因 此ConcreteComponent 和 Decorator 有着一个共同的父类。这里有人会问让 Decorator 直接维护一个指向 ConcreteComponent 引用指针 不就可以达到同样的效果 答案是肯定并且是否定的。 肯定的是你可以通过这种方式实现 否定的是你不要用这种方式实现 因为通过这种方式你就只能为这个特定的 ConcreteComponent 提供修饰操作了当有了一个新的ConcreteComponent 你又要去新建 一 个 Decorator 来 实 现 。 但是通过结构图中的ConcreteComponent 和 Decorator 有一个公共基类 就可以利用 OO 中多态的思想来实现只要是 Component 型别的对象都可以提供修饰操作的类这种情况下你就算新建了100个 。Component 型别的类 ConcreteComponent也都可以由 Decorator 一个类搞定。这也正是Decorator 模式的关键和威力所在了。当然如果你只用给 Component 型别类添加一种修饰 则 Decorator 这个基类就不是很必 要了。
没有用装饰器
// 普通员工有销售奖金累计奖金部门经理除此之外还有团队奖金后面可能会添加环比增长奖金同时可能产生不同的奖金组合
// 销售奖金 当月销售额 * 4%
// 累计奖金 总的回款额 * 0.2%
// 部门奖金 团队销售额 * 1%
// 环比奖金 (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
class Context {
public:bool isMgr;// User user;// double groupsale;
};class Bonus {
public:double CalcBonus(Context ctx) {double bonus 0.0;bonus CalcMonthBonus(ctx);bonus CalcSumBonus(ctx);if (ctx.isMgr) {bonus CalcGroupBonus(ctx);}return bonus;}
private:double CalcMonthBonus(Context ctx) {double bonus/* */;return bonus;}double CalcSumBonus(Context ctx) {double bonus/* */;return bonus;}double CalcGroupBonus(Context ctx) {double bonus/* */;return bonus;}
};int main() {Context ctx;// 设置 ctxBonus *bonus new Bonus;bonus-CalcBonus(ctx);
}#include iostream
// 普通员工有销售奖金累计奖金部门经理除此之外还有团队奖金后面可能会添加环比增长奖金同时可能产生不同的奖金组合
// 销售奖金 当月销售额 * 4%
// 累计奖金 总的回款额 * 0.2%
// 部门奖金 团队销售额 * 1%
// 环比奖金 (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
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 CalcMonthBonus(base);CalcBonus *cb2 new CalcSumBonus(cb1);cb2-Calc(ctx1);// 2. 部门经理Context ctx2;CalcBonus *cb3 new CalcGroupBonus(cb1);cb3-Calc(ctx2);
}