做网站美工要学什么,大联盟平台推广,品牌网站怎么做seo,wordpress 个人资料按钮写少量的代码来应对未来需求的变化。
单例模式
定义
保证一个类仅有一个实例#xff0c;并提供一个该实例的全局访问点。——《设计模式》GoF
解决问题
稳定点#xff1a;
类只有一个实例#xff0c;提供全局的访问点#xff08;抽象#xff09;
变化点#xff1a…写少量的代码来应对未来需求的变化。
单例模式
定义
保证一个类仅有一个实例并提供一个该实例的全局访问点。——《设计模式》GoF
解决问题
稳定点
类只有一个实例提供全局的访问点抽象
变化点 有多个类都是单例能不能复用代码扩展中的继承和组合
代码结构
私有的构造和析构禁掉拷贝构造、拷贝赋值、移动构造、移动赋值静态类成员函数静态私有成员变量访问方式: Singleton:Getlnstance()
版本一
把构造函数和析构函数私有化让别人不能调用它 因为只有一个示例所以我们要限定他的构造函数 并且提供一个全局访问点
class Singleton {
public:static Singleton * GetInstance() {//全局访问点if (_instance nullptr) {_instance new Singleton();}return _instance;}
private:Singleton(){}; //构造~Singleton(){};Singleton(const Singleton ) delete; //拷⻉
构造Singleton operator(const Singleton)
delete;//拷贝赋值构造Singleton(Singleton ) delete;//移动构造Singleton operator(Singleton )
delete;//移动拷贝构造static Singleton * _instance;
};Singleton* Singleton::_instance nullptr;//静态成
员需要初始化存在问题_instance是静态成员它没有释放没有delete这个然后我们看版本二
版本二
针对上面问题版本二可以主动调用 atexit(Destructor);
class Singleton {
public:static Singleton * GetInstance() {if (_instance nullptr) {_instance new Singleton();//这里多线程的话会产生多个atexit(Destructor);}return _instance;}
private:static void Destructor() {if (nullptr ! _instance) { //delete _instance;_instance nullptr;}}Singleton(){}; //构造~Singleton(){};Singleton(const Singleton ) delete; //拷⻉
构造Singleton operator(const Singleton)
delete;//拷贝赋值构造Singleton(Singleton ) delete;//移动构造Singleton operator(Singleton )
delete;//移动拷贝构造static Singleton * _instance;
};
Singleton* Singleton::_instance nullptr;//静态成
员需要初始化
// 还可以使⽤ 内部类智能指针来解决 此时还有线程安全问题存在问题版本二不能够多线程的。
版本三
然后就用到了加锁对于这个3.1和3.2很显然3.2这样效率更高因为读的时候不需要加锁只有写的时候才需要加锁。
#include mutex
class Singleton { // 懒汉模式 lazy load
public:static Singleton * GetInstance() {// std::lock_guardstd::mutex
lock(_mutex); // 3.1 切换线程if (_instance nullptr) {//双重检测std::lock_guardstd::mutex
lock(_mutex); // 3.2if (_instance nullptr) {//双重检测_instance new Singleton();// 1. 分配内存// 2. 调用构造函数// 3. 返回指针// 多线程环境下 cpu reorder操作atexit(Destructor);}}return _instance;}
private:static void Destructor() {if (nullptr ! _instance) {delete _instance;_instance nullptr;}}Singleton(){}; //构造~Singleton(){};Singleton(const Singleton ) delete; //拷⻉
构造Singleton operator(const Singleton)
delete;//拷贝赋值构造Singleton(Singleton ) delete;//移动构造Singleton operator(Singleton )
delete;//移动拷贝构造static Singleton * _instance;static std::mutex _mutex;
};
Singleton* Singleton::_instance nullptr;//静态成
员需要初始化
std::mutex Singleton::_mutex; //互斥锁初始化这里涉及到一个双重检测的问题因为读的时候不需要加锁只有写的时候才需要加锁然后这里很巧妙如果同时都进去第一个if语句的话一开始只有一个能拿到锁但是那个锁释放了同时都进去第一层训话的那写也可以去申请所以还要加上一个if这就是双重检测
if (_instance nullptr) {//双重检测std::lock_guardstd::mutex
lock(_mutex); // 3.2if (_instance nullptr) {//双重检测//操作}
}但是还是存在问题 多核时代它有一个编译器重排和cpu重排然后让他以更快的速度执行可能会违反顺序一致性。 然后C为了解决这个问题C用同步原语其中包括原子变量还要内存栅栏。 对于上面的代码我们虽然加了一把锁然后再new但是我们没有考虑指令重排这个问题。因为这个new还要很多操作。1. 分配内存2. 调用构造函数3. 返回指针。再多个时代下cpu可能会重排因为再单线程的时代下可能调用的是123.但是多线程可能调用的就是132。在其调用13之后就return了然后下一个线程来了之后执行if是空的然后它有调用了一次。
版本四
我们用原子语义也就是无锁编程。 原子执行的问题
可见性问题 load 可以看到其他线程最新操作的数据store 修改数据让其他线程可见 执行序问题 内存模型memory_order_qcquire和memory_order_release)
内存阑珊
可见性问题执行序问题 Singleton* tmp
_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acqui
re);//获取内存屏障if (tmp nullptr) {std::lock_guardstd::mutex
lock(_mutex);tmp
_instance.load(std::memory_order_relaxed);if (tmp nullptr) {tmp new Singleton;std::atomic_thread_fence(std::memory_order_relea
se);//释放内存屏障_instance.store(tmp,
std::memory_order_relaxed);atexit(Destructor);}}我们用原子变量解决原则性和可见性问题 内存栅栏解决执行序问题
// volitile
#include mutex
#include atomic
class Singleton {
public:static Singleton * GetInstance() {Singleton* tmp
_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acqui
re);//获取内存屏障if (tmp nullptr) {std::lock_guardstd::mutex
lock(_mutex);tmp
_instance.load(std::memory_order_relaxed);if (tmp nullptr) {tmp new Singleton;std::atomic_thread_fence(std::memory_order_relea
se);//释放内存屏障_instance.store(tmp,
std::memory_order_relaxed);atexit(Destructor);}}return tmp;}
private:static void Destructor() {Singleton* tmp
_instance.load(std::memory_order_relaxed);if (nullptr ! tmp) {delete tmp;}}Singleton(){}; //构造~Singleton(){};Singleton(const Singleton ) delete; //拷⻉
构造Singleton operator(const Singleton)
delete;//拷贝赋值构造Singleton(Singleton ) delete;//移动构造Singleton operator(Singleton )
delete;//移动拷贝构造static std::atomicSingleton* _instance;//原子变量static std::mutex _mutex;
};
std::atomicSingleton* Singleton::_instance;//静
态成员需要初始化
std::mutex Singleton::_mutex; //互斥锁初始化
// g Singleton.cpp -o singleton -stdc11多线程下无锁编程的单例模式就解决了。但是代码太长了。
版本五
我们直接构造一个static类型。 c11 magic static 特性如果当变量在初始化的时候并发同时进⼊声明语句并发线程将会阻塞等待初始化结束。static是线程安全的它再执行到下面之前都不会进行指令重排
// c effective
class Singleton
{
public:static Singleton GetInstance() {static Singleton instance;return instance;}
private:Singleton(){}; //构造~Singleton(){};Singleton(const Singleton ) delete; //拷⻉
构造Singleton operator(const Singleton)
delete;//拷贝赋值构造Singleton(Singleton ) delete;//移动构造Singleton operator(Singleton )
delete;//移动拷贝构造
};
// 继承 Singleton
// g Singleton.cpp -o singleton -stdc11
/*该版本具备 版本5 所有优点
1. 利⽤静态局部变量特性延迟加载
2. 利⽤静态局部变量特性系统⾃动回收内存⾃动调⽤析构函数
3. 静态局部变量初始化时没有 new 操作带来的cpu指令
reorder操作
4. c11 静态局部变量初始化时具备线程安全
*/版本六
这个就是实现一个多态因为如果有多个单例我们就不用都写那些重复的代码了。
templatetypename T
class Singleton {
public:static T GetInstance() {static T instance; // 这⾥要初始化
DesignPattern需要调⽤DesignPattern 构造函数同时会
调⽤⽗类的构造函数。return instance;}
protected://让子类得以构造virtual ~Singleton() {}Singleton() {} // protected修饰构造函数才能让
别⼈继承
private:Singleton(const Singleton ) delete; //拷⻉
构造禁用Singleton operator(const Singleton)
delete;//拷贝赋值构造Singleton(Singleton ) delete;//移动构造Singleton operator(Singleton )
delete;//移动拷贝构造
};
class DesignPattern : public
SingletonDesignPattern {friend class SingletonDesignPattern; //
friend 能让SingletonT 访问到 DesignPattern构造函数
private:DesignPattern() {}~DesignPattern() {}
};结构图 工厂模式
定义
定义一个用于创建对象的接口让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 ——《设计模式》GoF 为什么要有工厂模式而不直接使用new? 除了new还有复杂构造流程
解决问题
稳定性
创建同类对象的接口 对象创造接口同类对象有一个相同的职责 功能接口
变化点
创建对象的扩展
代码结构
实现该功能实现一个导出数据的接口让客户选择数据的导出方式xml,Json,txt,csv
没有使用工厂模式
#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;}
};// class ExportCSV : public IExport {
// public:
// virtual bool Export(const std::string data) {
// return true;
// }
// };// 1
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);}
}使用了工厂模式
#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;
}对象创建接口
创建具体对象调用功能接口
一个功能接口
设计原则 最小知道原则 面向接口编程
如何扩展代码
实现对象创建接口 实现功能接口 多态调用
总结
要点 解决创建过程比较复杂希望对外隐藏这些细节的场景
比如连接池、线程池隐藏对象真实类型对象创建会有很多参数来决定如何创建创建对象有复杂的依赖关系 本质 延迟到子类来选择实现 结构图
抽象工厂模式
定义
提供一个接口让该接口负责创建一系列“相关或者相互依赖的对象”无需指定它们具体的类。 ——《设计模式》GoF
解决问题
稳定性
创建同类对象的接口 对象创造接口同类对象有多个相同的职责 功能接口
变化点
创建对象的扩展
代码结构
实现一个拥有导出导入数据的接口让客户选择数据的导出导入方式 对象创建接口
创建具体对象提供多个功能结构来调用
多个功能接口
#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;
}工厂模式和抽象工厂模式的区别
抽象工厂需要创建一系列功能对象(多个功能接口)工厂方法创建一类功能的对象
结构图 责任链
其中negix就是用到了责任链
定义
使多个对象都有机会处理请求从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链并沿着这条链传递请求直到有一个对象处理它为止。 ——《设计模式》GoF 有多个处理者并且连成一个链当有一个处理了之后后面的就不用处理了。
解决问题
稳定点 处理流程
请求按照链条传递 链表关系接口 可打断
变化点
处理节点的个数处理顺序处理条件
代码框架
请求流程1 天内需要主程序批准3 天内需要项目经理批准3 天以上需要老板批准 首先不使用责任链模式
#include stringclass Context {
public:std::string name;int day;
};class LeaveRequest {
public:bool HandleRequest(const Context ctx) {if (ctx.day 1)HandleByBeaty(ctx);if (ctx.day 3)HandleByMainProgram(ctx);else if (ctx.day 10)HandleByProjMgr(ctx);elseHandleByBoss(ctx);}private:bool HandleByBeaty(const Context ctx) {}bool HandleByMainProgram(const Context ctx) {}bool HandleByProjMgr(const Context ctx) {}bool HandleByBoss(const Context ctx) {}
};符合设计原则 从单个节点出发 实现一个条件接口和构建链表关系的静态接口
实现处理功能 实现链条关系 实现功能传递功能
实现一个构建链表关系的静态接口 加入责任链之后的代码
#include stringclass 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;
}设计原则
组合优于继承面向接口编程接口依赖
扩展代码
实现处理接口
针对增加节点
修改静态接口
调整顺序添加节点或删除节点处理
总结
要点
解耦请求方和处理方请求方不知道请求是如何被处理处理方的组成是由相互独立的子处理构成子处理流程通过链表的方式连接子处理请求可以按任意顺序组合责任链请求强调请求最终由一个子处理流程处理通过了各个子处理条件判断责任链扩展就是功能链功能链强调的是一个请求依次经由功能链中的子处理流程处理将职责以及职责顺序运行进行抽象那么职责变化可以任意扩展同时职责顺序也可以任意扩展
本质 分离职责动态组合
结构图
装饰器
定义
动态地给一个对象增加一些额外的职责。就增加功能而言装饰器模式比生产子类更为灵活。 —— 《设计模式》GoF
解决问题
稳定点
顺序无关的增加职责 变化点增加
代码结构
普通员工有销售奖金累计奖金部门经理除此之外还有团队奖金后面可能会添加环比增长奖金同时可能针对不同的职位产生不同的奖金组合
没有设计模式
// 普通员工有销售奖金累计奖金部门经理除此之外还有团队奖金后面可能会添加环比增长奖金同时可能产生不同的奖金组合
// 销售奖金 当月销售额 * 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);
}
实现职责功能 protected 组合基类指针
通过继承基类扩展功能 通过依赖注入累加功能
设计原则
组合优于继承面向接口编程接口依赖
扩展代码
继承基类扩展功能通过依赖注入累加功能
总结
要点
通过采用组合而非继承的手法 装饰器模式实现了在运行时动态扩展对象功能的能力而且可以根据需要扩展多个功能。 避免了使用继承带来的“灵活性差”和“多子类衍生问题”。不是解决“多子类衍生问题”问题而是解决“父类在多个方向上的扩展功能”问题装饰器模式把一系列复杂的功能分散到每个装饰器当中一般一个装饰器只实现一个功能实现复用装饰器的功能
什么时候使用 不影响其他对象的情况下以动态、透明的方式给对象添加职责每个职责都是完全独立的功能彼此之间没有依赖 本质 动态组合 结构图
组合模式
定义
将对象组合成树型结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
解决问题
稳定点 “具备层次关系”稳定的 对象和组合对象可统一使用 变化点 对象的职责变更 组合对象里对象数量变更
什么时候使用组合模式
如果你想表示对象的部分-整体层次结构可以选用组合模式把整体和部分的操作统一起来使得层次结构实现更简单从外部来使用这个层次结构也容易如果你希望统一地使用组合结构中的所有对象可以选用组合模式这正是组合模式提供的主要功能
这种设计模式再游戏开发中特别常见。例如每一个用户玩家都有很多系统比如说签到系统宠物系统…。这些系统都会绑定在这个用户身上。然后这些宠物系统还有很多小功能。
代码结构
接口用于整合整体和部分的差异 叶子节点用于实现具体职责 组合节点职责委托叶子节点实现同时具备组合叶子节点职责最后执行的时候要给叶子节点执行
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::listIComponent* _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();}}
};
设计原则
组合优于继承面向接口编程接口依赖
扩展代码
继承接口实现职责组合整体和部分的关系 怎么实现 将叶子节点当成特殊的组合对象看待从而统一叶子对象和组合对象