设计模式(C++实现):单例模式,策略模式,责任链模式,装饰器模式

设计模式:

单例模式

  • 保证一个类只有一个实例,并提供一个该例的全局访问点。

  • 代码

    • 版本1
 class Singleton{
  public:
      static Singleton* getInstance(){
          if(_pInstance == nullptr){
              _pInstance = new Singleton();
          }
          return _pInstance;
      }
      
  private:
      Singleton();
      Singleton(const Singleton& clone);
      Singleton& operator=(const Singleton &);
  private:
      static Singleton* _pInstance;
  };
  /*存在的问题1.资源的回收问题
   *2.线程安全问题
  • 版本2
class Singleton{
    public:
        static Singleton* getInstance(){
            
            if(_pInstance == nullptr){
                _pInstance = new Singleton();
                atexit(Destructor());//进程退出的时候会执行
            }
            return _pInstance;
        }
        
    private:
        static void Destructor(){
            if(nullptr != _pInstance){
                delete _pInstance;
                _pInstance = nullptr;
            }
        }
        Singleton();
        Singleton(const Singleton& clone);
        Singleton& operator=(const Singleton &);
    private:
        static Singleton* _pInstance;
    };
    /*资源回收的解决办法:1.用atexit()函数回收
    2.智能指针托管,用栈的生命周期
    3.内部类,也是利用的栈上对象的生命周期
  • 版本3
 class Singleton{
    public:
        static Singleton* getInstance(){
            //std::lock_guard lock(std::mutex);粒度太大,存在隐患
            if(_pInstance == nullptr){
                std::lock_guard<std::mutex> lock(std::mutex);
                if(_pInstance == nullptr){
                    _pInstance = new Singleton();
                    atexit(Destructor());
                }            
            }
            return _pInstance;
        }
        
    private:
        static void Destructor(){
            if(nullptr != _pInstance){
                delete _pInstance;
                _pInstance = nullptr;
            }
        }
        Singleton(); 
        Singleton(const Singleton& clone);
        Singleton& operator=(const Singleton &);
    private:
        static Singleton* _pInstance;
        std::mutex _mutex;
    };
    Singleton* Singleton::_pInstance = nullptr;
    std::mutex Singlenton::_mutex;
    /*解决线程安全问题:1.加锁
    2.pthread_once();只执行一次
    ```
  • 版本4
 ```c++
    #include 
    #include 
    class Singleton {
    public:
     	static Singleton * GetInstance() {
     	Singleton* tmp = _instance.load(std::memory_order_relaxed);
     	std::atomic_thread_fence(std::memory_order_acquire);//获取内存屏障
     	if (tmp == nullptr) {
     		std::lock_guard<std::mutex> lock(_mutex);
     		tmp = _instance.load(std::memory_order_relaxed);
     		if (tmp == nullptr) {
     			tmp = new Singleton;
     			std::atomic_thread_fence(std::memory_order_release);//释放内存屏
    障
     			_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(const Singleton&) {}
    	Singleton& operator=(const Singleton&) {}
     	static std::atomic<Singleton*> _instance;
     	static std::mutex _mutex;
    };
    std::atomic<Singleton*> Singleton::_instance;//静态成员需要初始化
    std::mutex Singleton::_mutex; //互斥锁初始化
    // g++ Singleton.cpp -o singleton -std=c++11
    //使用内存屏障保证该代码的一次性
    ```
  • 版本5

    //C++11 magic static 特性:如果当变量在初始化的时候,并发同时进⼊声明语句,并发
    //线程将会阻塞等待初始化结束。
    class Singleton{
    public:
        static Singleton& getInstance(){
            static Singleton _Instance; 
            return _Instance; 
        }
        
    private:
        Singleton();
        Singleton(const Singleton& clone);
        Singleton& operator=(const Singleton &);
    };
    // 继承 Singleton
    // g++ Singleton.cpp -o singleton -std=c++11
    /*该版本具备 版本5 所有优点:
    1. 利⽤静态局部变量特性,延迟加载;
    2. 利⽤静态局部变量特性,系统⾃动回收内存,⾃动调⽤析构函数;
    3. 静态局部变量初始化时,没有 new 操作带来的cpu指令reorder操作;
    4. c++11 静态局部变量初始化时,具备线程安全;
    */
    
  • 版本6

    template<typename T> 
    class Singleton{
    public:
        static T & getInstance(){
            static T _Instance; // 这⾥要初始化DesignPattern,需要调⽤DesignPattern 构造函数,同时会调⽤⽗类的构造函数。
            return _Instance; 
        }
    protected:
        virtual ~Singleton();
        Singleton();// protected修饰构造函数,才能让别⼈继承
        Singleton(const T & clone);
        Singleton& operator=(const T &);
    };
    class DessignPattern
    :public Singleton<DessignPattern>
    {
        friend class Singleton<DessignPattern>; // friend 能让 Singleton 访问到DesignPattern构造函数
    private:
        DessignPattern();
        DessignPattern(const DessignPattern& );
        DessignPattern& operator=(const DessignPattern& );
    }
    
    
  • 结构图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mqr3M3fn-1639731122519)(C:\Users\HASEE\AppData\Roaming\Typora\typora-user-images\image-20211217150307758.png)]

策略模式

  • 定义

    定义一系列算法,把它们一个个封装起来,并且使他们可以互相替换,该模式使得算法可以独立于使用它的客户程序而变化

  • 背景

    某商场节假⽇有固定促销活动,为了加⼤促销⼒度,现提升国庆节促销活动规格;

  • 代码

    //原版代码
    enum VacationEnum{
      	VAC_Spring,
        VAC_Qixi,
        VAC_Duoqing
        //...  
    };
    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){
    			// 国庆
    		}
        }
    };
    
    //----------------------------------------------------------------------------
    enum Context{
      	VAC_Spring,
        VAC_Qixi,
        VAC_Duoqing
        //...  
    };
    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_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:
        double CalcPromotion(ProStategy* sss)
        :_s(sss)
        {
        }
        ~Promotion();
        double CalcPromotion(const Context& ctx){
            _s->CalcPro(ctx);
    	}
    private:
        ProStategy* _s;
    };
    
    int main(){
        Context ctx;
        ProStategy *s = new VAC_Spring();
        Promotion p(s);
        p.CalcPromotion(ctx);
        return;
    }
    
  • 要点

    策略模式提供了⼀系列可重⽤的算法,从⽽可以使得类型在运⾏时⽅便地根据需要在各个算法

    之间进⾏切换;策略模式消除了条件判断语句;就是在解耦合;充分体现了开闭原则;单⼀职责;

  • 本质

    分离算法,选择实现;

  • 结构图

设计模式(C++实现):单例模式,策略模式,责任链模式,装饰器模式_第1张图片

责任链模式

  • 定义

    使多个对象都有机会处理请求,从⽽避免请求的发送者和接收者之间的耦合关系。将这些对象连成⼀条链,并沿着这条链传递请求,直到有⼀个对象处理它为⽌。 ——《设计模式》GoF

  • 背景

    请假流程,1天内需要主程序批准,3天内需要项⽬经理批准,3天以上需要⽼板批准;

  • 代码

    //nginx 阶段处理
    // 严格意义说是功能链
    // ngx_http_init_phase_handlers 初始化责任链 cmcf->phase_engine.handlers
    // ngx_http_core_run_phases 调⽤责任链**要点**
    
    class Context{
    public:
        std::string name;
        int day;
    };
    
    class LeaveRequest{
    public:
        bool HandleRequest(const Context& ctx){
            //可以将具体的处理流程抽象
         	if(ctx.day <= 3)//判断逻辑抽象
                HandleByMainProgram(ctx);
            else if(ctx.day <= 10)
                HandleByProjMgr(ctx);
            else
                HandleByBoss(ctx);
        }
    private:
        //职责抽象
        bool HandleByMainProgram(const Context &ctx) {
            //...
        }
        bool HandleByProjMgr(const Context &ctx) {
            //...
        }
        bool HandleByBoss(const Context &ctx) {
    		//...
        }
    };
    
    //---------------------------------------------------------------------------
    class Context{
    public:
        std::string name;
        int day;
    };
    
    class IHandler{
    public://对外提供的接口,设置链式的处理逻辑和处理的数据
        virtual ~IHandler();
        //责任链,往后面链起来,逻辑处理往后传递
        void SetNextHandler(IHandler* next){
            _next = next;
        }
        bool Handle(const Context* ctx){
            if(CanHandle*(ctx)){//当前能处理,就返回
                return HandleRequest(ctx);
            }else{
                return GetNextHandler()->HandleRequest(ctx);//当前不能处理,就往后传递
            }
        }
    protected://对子类继承的接口,具体的处理,判断是否可以处理,不能处理时传递的下一级
        virtual bool HandleRequest(const Context* ctx) = 0;
        virtual bool CanHandle(const Context* ctx) = 0;
        virtual GetNextHandler() = 0;
    private:
    	IHandler* _next;
    };
    
    class HandleByMainProgram : public IHandler {
    protected:
        virtual bool HandleRequest(const Context &ctx){
            //...
        }
        virtual bool CanHandle() {
            //...
        }
    };
    
    class HandleByProjMgr : public IHandler {
    protected:
        virtual bool HandleRequest(const Context &ctx){
            //
        }
        virtual bool CanHandle() {
            //
        }
    };
    
    class HandleByBoss : public IHandler {
    public:
        virtual bool HandleRequest(const Context &ctx){
            //
        }
    protected:
        virtual bool CanHandle() {
            //
        }
    };
    
    int main(){
        IHandler* p0 = new HandleByMainProgram();
        IHandler* p1 = new HandleByProjMgr();
        IHandler* p2 = new HandleByBoss();
        p1->SetNextHandler(p0);
        
        Context ctx;
        p1->handle(ctx);
        return 0;
    }
    
    
  • 要点

    • 解耦请求⽅和处理⽅,请求⽅不知道请求是如何被处理,处理⽅的组成是由相互独⽴的⼦处理
    • 构成,⼦处理流程通过链表的⽅式连接,⼦处理请求可以按任意顺序组合;
    • 责任链请求强调请求最终由⼀个⼦处理流程处理;通过了各个⼦处理条件判断;
    • 责任链扩展就是功能链,功能链强调的是,⼀个请求依次经由功能链中的⼦处理流程处理;
    • 充分体现了单⼀职责原则;将职责以及职责顺序运⾏进⾏抽象,那么职责变化可以任意扩展,同时职责顺序也可以任意扩展;
  • 本质

    分离职责,动态组合;

  • 结构图

设计模式(C++实现):单例模式,策略模式,责任链模式,装饰器模式_第2张图片

装饰器模式

  • 定义

    动态地给⼀个对象增加⼀些额外的职责。就增加功能⽽⾔,装饰器模式⽐⽣成⼦类更为灵活。 ——《设计模式》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;
        // 设置 ctx
        Bonus *bonus = new Bonus;
        bonus->CalcBonus(ctx);
    }
    
    //----------------------------------------------------------------------------
    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);
    }
    
    
        
    
  • 要点

    通过采⽤组合⽽⾮继承的⼿法, 装饰器模式实现了在运⾏时动态扩展对象功能的能⼒,⽽且可以根据需要扩展多个功能。 避免了使⽤继承带来的“灵活性差”和“多⼦类衍⽣问题”。不是解决“多⼦类衍⽣的多继承”问题,⽽是解决“⽗类在多个⽅向上的扩展功能”问题;装饰器模式把⼀系列复杂的功能分散到每个装饰器当中,⼀般⼀个装饰器只实现⼀个功能,实现复⽤装饰器的功能;

  • 本质

    动态组合

  • 结构图

  • 设计模式(C++实现):单例模式,策略模式,责任链模式,装饰器模式_第3张图片

你可能感兴趣的:(设计模式,单例模式,c++,策略模式)