设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案;是软件开发中解决问题的固定套路;
使用设计模式的前提是具体需求的既有稳定点和又有变化点;全是稳定点和全是变化点是没有必要使用设计模式的;期望修改少量的代码就可以适应需求的变化;比喻:整洁的房间,有一个好动的猫,怎么保证房间的整洁?把猫关起来;
设计模式的基础;1、有面向对象思想:封装,继承,多态;
2、设计原则:1)依赖倒置,接口的使用者不要依赖具体的实现,而应该依赖具体接口;1)开闭原则,对扩展开放,对修改关闭,主要针对封装和多态;2)面向接口,主要针对封装;3)封装变化点,主要针对封装和多态;4)单一职责,主要针对封装;5)理氏替换,主要针对多态;6)接口隔离;7)组合优于继承;8)最少知道原则,封装相关;
模板方法
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤;
解决问题;稳定点是算法骨架,变化点是子流程需要变化;
代码结构
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(); zs1->Show(); zs2->Show(); return 0; }
观察者模式
定义对象的一种一对多的依赖关系,以便当一个对象状态发生变化的时候,所有依赖于它的对象得到通知并自动更新;
解决问题;稳定点是一对多的依赖关系,“一”变化时,“多”跟着变化;变化点是“多”增加或减少;
实例:气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到两个不同的显示终端;
代码结构
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::list<IDisplay*> 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(); return 0; }
策略模式
定义一系列算法,把他们一个个封装起来,并使他们能互相替换,该模式使得算法可以独立于使用它的客户端程序而变化;
解决问题;稳定点是客户程序与算法的调用关系,变化点是算法会发生变化或替换;
实例;某商场节假日有固定促销活动,为了加大促销力度,现提升国庆节促销活动规格;
代码结构
class Context { }; // 变化点:扩展(继承和组合)去解决它 // 稳定点:抽象去解决它 class ProStategy { public: virtual double CalcPro(const Context &ctx) = 0; virtual ~ProStategy(); }; class VAC_Spring : public ProStategy { public: virtual double CalcPro(const Context &ctx){} }; 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){} }; class VAC_Wuyi : public ProStategy { public: virtual double CalcPro(const Context &ctx){} }; 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; }
工厂模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使得一个类的实例化延迟到子类;
解决创建过程比较复杂,希望对外隐藏这些细节的场景;
1、比如连接池、线程池
2、隐藏对象真实类型;
3、对象创建会有很多参数来决定如何创建;
4、创建对象有复杂的依赖关系;
实例;实现一个导出数据的接口,让客户选择数据的导出方式;
代码结构
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式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; }
抽象工厂
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
实例;实现一个拥有导出导入数据的接口,让客户选择数据的导出导入方式;
代码结构
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式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; }
责任链
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
要点:
1、解耦请求方和处理方,请求方不知道请求是如何被处理,处理方的组成是由相互独立的子处理构成,子处理流程通过链表的方式连接,子处理请求可以按任意顺序组合;
2、责任链请求强调请求最终由一个子处理流程处理;通过了各个子处理条件判断;
3、责任链扩展就是功能链,功能链强调的是,一个请求依次经由功能链中的子处理流程处理;
4、将职责以及职责顺序运行进行抽象,那么职责变化可以任意扩展,同时职责顺序也可以任意扩展;
实例;请求流程,1 天内需要主程序批准,3 天内需要项目经理批准,3天以上需要老板批准;
代码结构
class Context { public: std::string name; int day; }; // 稳定点 抽象 变化点 扩展 (多态) // 从单个处理节点出发,我能处理,我处理,我不能处理交给下一个人处理 // 链表关系如何抽象 class IHandler { public: virtual ~IHandler() : next(nullptr) {} void SetNextHandler(IHandler *next) { // 链表关系 next = next; } bool Handle(const Context &ctx) { if (CanHandle(ctx)) { return HandleRequest(ctx); } else if (GetNextHandler()) { return GetNextHandler()->Handle(ctx); } else { // err } return false; } // 通过函数来抽象 处理节点的个数 处理节点顺序 static bool handler_leavereq(Context &ctx) { IHandler * h0 = new HandleByBeauty(); IHandler * h1 = new HandleByMainProgram(); IHandler * h2 = new HandleByProjMgr(); IHandler * h3 = new HandleByBoss(); h0->SetNextHandler(h1); h1->SetNextHandler(h2); h2->SetNextHandler(h3); return h0->Handle(ctx); } protected: virtual bool HandleRequest(const Context &ctx) {return true}; virtual bool CanHandle(const Context &ctx) {return true}; IHandler * GetNextHandler() { return next; } private: IHandler *next; // 组合基类指针 }; // 能不能处理,以及怎么处理 class HandleByMainProgram : public IHandler { protected: virtual bool HandleRequest(const Context &ctx){ return true; } virtual bool CanHandle(const Context &ctx) { if (ctx.day <= 10) return true; return false; } }; class HandleByProjMgr : public IHandler { protected: virtual bool HandleRequest(const Context &ctx){ return true; } virtual bool CanHandle(const Context &ctx) { if (ctx.day <= 20) return true; return false; } }; class HandleByBoss : public IHandler { protected: virtual bool HandleRequest(const Context &ctx){ return true; } virtual bool CanHandle(const Context &ctx) { if (ctx.day < 30) return true; return false; } }; class HandleByBeauty : public IHandler { protected: virtual bool HandleRequest(const Context &ctx){ return true; } virtual bool CanHandle(const Context &ctx) { if (ctx.day <= 3) return true; return false; } }; int main() { // IHandler * h1 = new HandleByMainProgram(); // IHandler * h2 = new HandleByProjMgr(); // IHandler * h3 = new HandleByBoss(); // h1->SetNextHandler(h2); // h2->SetNextHandler(h3); // 抽象工厂 // nginx http 处理 // 设置下一指针 Context ctx; if (IHander::handler_leavereq(ctx)) { cout << "请假成功"; } else { cout << "请假失败"; } return 0; }
装饰器
动态地给一个对象增加一些额外的职责。就增加功能而言,装饰器模式比生产子类更为灵活。
要点
1、通过采用组合而非继承的手法, 装饰器模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。 避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
2、不是解决“多子类衍生问题”问题,而是解决“父类在多个方向上的扩展功能”问题;
3、装饰器模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,实现复用装饰器的功能;
实例;普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能针对不同的职位产生不同的奖金组合;
代码结构
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); }
组合模式
将对象组合成树型结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
如果你想表示对象的部分-整体层次结构,可以选用组合模式,把整体和部分的操作统一起来,得层次结构实现更简单,从外部来使用这个层次结构也容易;如果你希望统一地使用组合结构中的所有对象,可以选用组合模式,这正是组合模式提供的主要功能;
将叶子节点当成特殊的组合对象看待,从而统一叶子对象和组合对象;
代码结构
class IComponent { public: IComponent(/* args */); ~IComponent(); virtual void Execute() = 0; virtual void AddChild(IComponent *ele) {} virtual void RemoveChild(IComponent *ele) {} }; class Leaf : public IComponent { public: virtual void Execute() { cout << "leaf exxcute" << endl; } }; class Composite : public IComponent { private: std::list<IComponent*> _list; public: virtual void AddChild(IComponent *ele) { // ... } virtual void RemoveChild(IComponent *ele) { // ... } virtual void Execute() { for (auto iter = _list.begin(); iter != _list.end(); iter++) { iter->Execute(); } } };