前言
有关设计模式的其他常用模式请参考
单例模式的实现
常见的设计模式(模板与方法,观察者模式,策略模式)
工程方法
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 ——《设计模式》GoF
要点
解决创建过程比较复杂,希望对外隐藏这些细节的场景;
比如连接池、线程池
隐藏对象真实类型;
对象创建会有很多参数来决定如何创建;
创建对象有复杂的依赖关系;
本质
延迟到子类来选择实现;
结构图
举例
实现一个导出数据的接口,让客户选择数据的导出方式;
代码
class IExport { protected: IExport() {} virtual ~IExport() {} public: virtual void exportFile() = 0; }; class JSONExport :public IExport { public: JSONExport() {} ~JSONExport() {} void exportFile() { std::cout << "export json file" << std::endl; } }; class TxtFileExport :public IExport { public: TxtFileExport() {} ~TxtFileExport() {} void exportFile() { std::cout << "export txt file" << std::endl; } }; class XMLExport :public IExport { public: XMLExport() {} ~XMLExport() {} void exportFile() { std::cout << "export xml file" << std::endl; } }; class IFactoryMethodExport { public: virtual IExport* createExport() = 0;//创建比较复杂,使用一个函数来创建 }; class FactoryMethodJSONExport :public IFactoryMethodExport { public: IExport* createExport() { //比较多的参数初始化 jsonExport = new JSONExport();//这里没有使用参数这些 //其他初始化操作 } private: JSONExport* jsonExport; }; class FactoryMethodXMLExport :public IFactoryMethodExport { public: IExport* createExport() { //比较多的参数初始化 xmlExport = new XMLExport();//这里没有使用参数这些 //其他初始化操作 } private: XMLExport* xmlExport; }; class FactoryMethodTxtFileExport :public IFactoryMethodExport { public: IExport* createExport() { //比较多的参数初始化 txtFileExport = new TxtFileExport();//这里没有使用参数这些 //其他初始化操作 return txtFileExport; } private: TxtFileExport* txtFileExport; };
抽象工厂
定义
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。——《设计模式》GoF
其实和工厂方法是类似的,只是在工厂中创建多个对象。
结构图
例子
实现一个拥有导出导入数据的接口,让客户选择数据的导出导入方式;
代码
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; } }; // 对于初学者: 知道扩展代码 // 5年 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; }
责任链模式
定义
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 ——《设计模式》GoF
要点
解耦请求方和处理方,请求方不知道请求是如何被处理,处理方的组成是由相互独- 立的子处理构成,子处理流程通过链表的方式连接,子处理请求可以按任意顺序组合;
责任链请求强调请求最终由一个子处理流程处理;通过了各个子处理条件判断;
责任链扩展就是功能链,功能链强调的是,一个请求依次经由功能链中的子处理流程处理;
将职责以及职责顺序运行进行抽象,那么职责变化可以任意扩展,同时职责顺序也可以任意扩展;
本质
分离职责,动态组合;
结构图
例子
请求流程,1 天内需要主程序批准,3 天内需要项目经理批准,3 天以上需要老板批准;
在前面链接的说明了设计模式主要是设计需求的变化点,稳定点是固定的流程。
在这里:稳定点是处理流程是稳定的(首选判断是否能够处理,如果不能处理,则交给更高层处理,可以抽象出是否能够处理接口和处理接口)。变化点包括:天数,职责人个数(后续可能会增加更多的项目职责)。
代码
#include <string> struct WorkerContext { std::string name; int day; }; class IWorker{ public: IWorker(WorkerContext& context) :context(context) { } //处理流程是固定的,稳定点不变 bool handle() { if (isCanHandle()) {//可以处理 return handRequest(); } else if(next){//不可以处理,交给下个处理者处理 return next->handle(); } std::cout << "无法处理" << std::endl; return false; } void setNextHandler(IWorker* _next)//设置下一个处理者 { next = _next; } protected: virtual bool isCanHandle() = 0;//是否可以处理 virtual bool handRequest() = 0;//处理 WorkerContext& context; private: IWorker* next = nullptr;//下一个流程处理者 }; // class MainProgram :public IWorker { public: MainProgram(WorkerContext& context) :IWorker(context) {} private: bool isCanHandle() { if (context.day <= 1) { return true; } return false; } bool handRequest() { std::cout << "MainProgram 同意" << context.name << "天数" << context.day << std::endl; return true; } }; class ProjectManager :public IWorker { public: ProjectManager(WorkerContext& context) :IWorker(context) {} private: bool isCanHandle() { if (context.day <= 3) { return true; } return false; } bool handRequest() { std::cout << "ProjectManager 同意" << context.name << "天数" << context.day << std::endl; return true; } }; class Boss :public IWorker { public: Boss(WorkerContext& context) :IWorker(context) {} private: bool isCanHandle() { if (context.day > 3 && context.day < 10) { return true; } return false; } bool handRequest() { std::cout << "Boss 同意" << context.name << "天数" << context.day << std::endl; return true; } }; int main{ WorkerContext context; context.day = 10; context.name = "susan"; IWorker* worker1 = new MainProgram(context); IWorker* worker2 = new ProjectManager(context); IWorker* worker3 = new Boss(context); worker1->setNextHandler(worker2); worker2->setNextHandler(worker3); worker1->handle(); }
装饰器模式
定义
动态地给一个对象增加一些额外的职责。就增加功能而言,装饰器模式比生产子类更为灵活。—— 《设计模式》GoF
要点
- 通过采用组合而非继承的手法, 装饰器模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。 避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
- 不是解决“多子类衍生问题”问题,而是解决“父类在多个方向上的扩展功能”问题;
- 装饰器模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,实现复用装饰器的功能;
本质
动态组合
例子
普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能针对不同的职位产生不同的奖金组合;
代码
#include <iostream> // 普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能产生不同的奖金组合; // 销售奖金 = 当月销售额 * 4% // 累计奖金 = 总的回款额 * 0.2% // 部门奖金 = 团队销售额 * 1% // 环比奖金 = (当月销售额-上月销售额) * 1% // 销售后面的参数可能会调整 using namespace std; class Context { public: bool isMgr; // User user; // double groupsale; };