策略模式
- 定义
定义⼀系列算法,把它们⼀个个封装起来,并且使它们可互相替换。该模式使得算法可独⽴于使⽤
它的客户程序⽽变化。 - 要点
- 策略模式提供了⼀系列可重⽤的算法,从⽽可以使得类型在运⾏时⽅便地根据需要在各个算法
之间进⾏切换; - 策略模式消除了条件判断语句;就是在解耦合;
- 充分体现了开闭原则,单⼀职责;
- 策略模式提供了⼀系列可重⽤的算法,从⽽可以使得类型在运⾏时⽅便地根据需要在各个算法
- 本质
分离算法,选择实现; - 例子
某商场节假⽇有固定促销活动,为了加⼤促销⼒度,现提升节日促销活动规格; - 代码
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_XXXXX : 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_Spring ();
Promotion *p = new Promotion(s);
p->CalcPromotion(ctx);
return 0;
}
责任链模式
-
定义
使多个对象都有机会处理请求,从⽽避免请求的发送者和接收者之间的耦合关系。将这些对象连成
⼀条链,并沿着这条链传递请求,直到有⼀个对象处理它为⽌。 -
要点
- 解耦请求⽅和处理⽅,请求⽅不知道请求是如何被处理,处理⽅的组成是由相互独⽴的⼦处理
构成,⼦处理流程通过链表的⽅式连接,⼦处理请求可以按任意顺序组合; - 责任链请求强调请求最终由⼀个⼦处理流程处理;通过了各个⼦处理条件判断;
- 责任链扩展就是功能链,功能链强调的是,⼀个请求依次经由功能链中的⼦处理流程处理;
- 充分体现了单⼀职责原则;将职责以及职责顺序运⾏进⾏抽象,那么职责变化可以任意扩展,
同时职责顺序也可以任意扩展;
- 解耦请求⽅和处理⽅,请求⽅不知道请求是如何被处理,处理⽅的组成是由相互独⽴的⼦处理
-
本质
分离职责,动态组合; -
例子
请假流程,1天内需要主程序批准,3天内需要项⽬经理批准,3天以上需要⽼板批准; -
代码
#include <string>
class Context {
public:
std::string name;
int day;
};
class IHandler {
public:
virtual ~IHandler() {}
void SetNextHandler(IHandler *next) {
next = next;
}
bool Handle(ctx) {
if (CanHandle(ctx)) {//如果可以处理本请求
return HandleRequest();//进行处理
} else if (GetNextHandler()) {//否则交给下一个handler处理
return GetNextHandler()->HandleRequest(ctx);
} else {
// err
}
}
protected:
virtual bool HandleRequest(const Context &ctx) = 0;
virtual bool CanHandle(const Context &ctx) =0;
IHandler * GetNextHandler() {
return next;
}
private:
IHandler *next;
};
//主程
class HandleByMainProgram : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
}
virtual bool CanHandle() {
//
}
};
//PM
class HandleByProjMgr : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
}
virtual bool CanHandle() {
//
}
};
//BOSS
class HandleByBoss : public IHandler {
public:
virtual bool HandleRequest(const Context &ctx){
//
}
protected:
virtual bool CanHandle() {
//
}
};
int main () {
IHandler * h1 = new MainProgram();
IHandler * h2 = new HandleByProjMgr();
IHandler * h3 = new HandleByBoss();
h1->SetNextHandler(h2);
h2->SetNextHandler(h3)
Context ctx;
h1->handle(ctx);
return 0;
}
装饰器模式
-
定义
动态地给⼀个对象增加⼀些额外的职责。就增加功能⽽⾔,装饰器模式⽐⽣成⼦类更为灵活。 -
要点
- 通过采⽤组合⽽⾮继承的⼿法, 装饰器模式实现了在运⾏时动态扩展对象功能的能⼒,⽽且
可以根据需要扩展多个功能。 避免了使⽤继承带来的“灵活性差”和“多⼦类衍⽣问题”。 - 不是解决“多⼦类衍⽣的多继承”问题,⽽是解决“⽗类在多个⽅向上的扩展功能”问题;
- 装饰器模式把⼀系列复杂的功能分散到每个装饰器当中,⼀般⼀个装饰器只实现⼀个功能,实
现复⽤装饰器的功能;
- 通过采⽤组合⽽⾮继承的⼿法, 装饰器模式实现了在运⾏时动态扩展对象功能的能⼒,⽽且
-
本质
动态组合 -
例子
普通员⼯有销售奖⾦,累计奖⾦,部⻔经理除此之外还有团队奖⾦;后⾯可能会添加环⽐增⻓奖
⾦,同时可能针对不同的职位产⽣不同的奖⾦组合;
-
代码
// 普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能产生不同的奖金组合;
// 销售奖金 = 当月销售额 * 4%
// 累计奖金 = 总的回款额 * 0.2%
// 部门奖金 = 团队销售额 * 1%
// 环比奖金 = (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
class Context {
public:
bool isMgr;
// User user;
// double groupsale;
};
// 试着从职责出发,将职责抽象出来
class CalcBonus {
public:
CalcBonus(CalcBonus * c = nullptr) {}
virtual double Calc(Context &ctx) {
return 0.0; // 基本工资
}
virtual ~CalcBonus() {}
protected:
CalcBonus* cc;
};
class CalcMonthBonus : public CalcBonus {
public:
CalcMonthBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double mbonus /*= 计算流程忽略*/;
return mbonus + cc->Calc(ctx);
}
};
class CalcSumBonus : public CalcBonus {
public:
CalcSumBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double sbonus /*= 计算流程忽略*/;
return sbonus + cc->Calc(ctx);
}
};
class CalcGroupBonus : public CalcBonus {
public:
CalcGroupBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
class CalcCycleBonus : public CalcBonus {
public:
CalcGroupBonus(CalcBonus * c) : cc(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(cb2);
cb3->Calc(ctx2);
}
工厂模式
- 定义
定义⼀个⽤于创建对象的接⼝,让⼦类决定实例化哪⼀个类。Factory Method使得⼀个类的实例化
延迟到⼦类。 - 要点
- 解决创建过程⽐较复杂,希望对外隐藏这些细节;
- ⽐如连接池,线程池;
- 隐藏对象真实类型;
- 对象创建会有很多参数来决定如何创建;
- 创建对象有复杂的依赖关系;
- 解决创建过程⽐较复杂,希望对外隐藏这些细节;
- 本质
延迟到⼦类来选择实现; - 例子
实现⼀个导出数据的接⼝,让客户选择数据的导出⽅式; - 代码
#include <string>
// 实现导出数据的接口, 导出数据的格式包含 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 ExportTxtFactory();
factory->Export("hello world");
return 0;
}
抽象工厂模式
-
定义
提供⼀个接⼝,让该接⼝负责创建⼀系列“相关或者相互依赖的对象”,⽆需指定它们具体的类。 -
例子
实现⼀个拥有导出导⼊数据的接⼝,让客户选择数据的导出导⼊⽅式; -
代码(只不过是把api封装在了一起而已,上面那个是只有导出操作,而这个支持导入导出等等)
#include <string>
// 实现导出数据的接口, 导出数据的格式包含 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;
}
代理模式
- 定义
为其他对象提供⼀种代理以控制对这对象的访问。 - 应用
- 远程代理(隐藏⼀个对象存在不同的地址空间的事实),虚代理(延迟加载lazyload),保护
代理(在代理前后做额外操作,权限管理,引⽤计数等); - 在分布式系统中,actor模型(skynet)等常⽤的设计模式;
- 远程代理(隐藏⼀个对象存在不同的地址空间的事实),虚代理(延迟加载lazyload),保护
- 本质
控制对象访问; - 例子
在有些系统中,为了某些对象的纯粹性,只进⾏了功能相关封装(稳定点),后期添加了其他功能
需要对该对象进⾏额外操作(变化点),为了隔离变化点(也就是不直接在稳定点进⾏修改,这样
会让稳定点也变得不稳定),可以抽象⼀层代理层; - 代码
class ISubject {
public:
virtual void Handle() = 0;
virtual ~ISubject() {}
};
// 该类在当前进程,也可能在其他进程当中
class RealSubject : public ISubject {
public:
virtual void Handle() {
// 只完成功能相关的操作,不做其他模块的判断
}
};
// 在当前进程当中 只会在某个模块中使用
class Proxy1 : public ISubject {
public:
Proxy1(ISubject *subject) : _subject(subject) {}
virtual void Handle() {
// 在访问 RealSubject 之前做一些处理
//if (不满足条件)
// return;
_subject->Handle();
count++;
// 在访问 RealSubject 之后做一些处理
}
private:
ISubject* _subject;
static int count;
};
int Proxy1::count = 0;
// 在分布式系统当中 skynet actor
class Proxy2 : public ISubject {
public:
virtual void Handle() {
// 在访问 RealSubject 之前做一些处理
// 发送到数据到远端 网络处理
//IResult * val = rpc->call("RealSubject", "Handle");
// 在访问 RealSubject 之后做一些处理
}
private:
/*void callback(IResult * val) {
// 在访问 RealSubject 之后做一些处理
}*/
};