zoukankan      html  css  js  c++  java
  • 【设计模式】观察者模式(改进后的)

     

    前言

    之前  观察者模式一篇 中,【通知者】需要知道【观察者】的类名和更新函数名,耦合度稍大,本篇稍稍修改一下,类似于大话设计模式里的C#描述的委托事件的方法。

    采用 将类成员函数指针转换为普通指针 的方式,把每个【观察者】类的 相同原型的更新函数 指针转换为std::function然后保存起来。

    然后在【通知者】的 通知函数 中调用保存起来的每个 【观察者】的更新函数。

    本文去除了【观察者】的继承结构,【通知者】只需要知道每个【观察者】的更新函数原型。 

    去除了继承结构,因此每个【观察者】的更新函数也就不必是virtual的了。

     

     描述

    /************************************************************************/
    /* 设计模式
       观察者模式 
       本文介绍一种解耦的方法,使【通知者】不依赖于【观察者】
       即【通知者】不知道【观察者】的太多细节,只需要知道【观察者】
       的【更新函数原型】,所以这就要求【观察者】的更新函数的原型
       要一致。
    
       以【大话设计模式】里的讲到的Visual Studio的窗口变化为例: 
       当【启动调试】时,【输出】窗口展开,【反汇编】窗口展开
       当【结束调试】时,【输出】窗口隐藏,【反汇编】窗口隐藏
       所以这里的【通知者】为【调试器】,【观察者】为【输出】和【反汇编】窗口
    /************************************************************************/
     
    
    //调试器的两个行为:启动 和 停止
    typedef enum _ESubjectState{Start = 0, End = 1}ESubjectState; 
     

     

    所需头文件

    #include "stdafx.h"
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <functional>
    using namespace std;

     PS:

    说到头文件,不得不PS一下下,看头文件里的map,由于在用vector保存std::function时,不能使用std::find函数,也不能在for(iter)中使用if(*iter == std::function XX),因此我试图使用map来保证保存std::functiond唯一性,用map的find来查找待删除的观察者的更新函数。

    是试图!!!  经过测试,发现还是不行!

    在VC群里HB说因为std::function没有operator ==, 因此不能使用std::find函数, 因此也不能if(*iter == std::function XX),我想map可能是同样的原因。

     

     

    两个观察者

    观察者1:输出窗口类

    //【观察者】--【输出窗口类】
    class COutputWnd 
    {
    public: 
        COutputWnd();
        virtual ~COutputWnd();
        void UpdateOutWnd(ESubjectState e);  //更新状态
    };
    
    COutputWnd::COutputWnd(){}
    COutputWnd::~COutputWnd(){}
    void COutputWnd::UpdateOutWnd(ESubjectState e)
    {
        switch(e)
        {
        case Start:
            cout<<"调试器启动了,展开 输出窗口 
    ";
            break;
        case End:
            cout<<"调试器关闭了,收起 输出窗口 
    ";
        default:
            break;
        } 
    }

     

     

     

    观察者2:反汇编窗口类

    //【观察者】--【反汇编窗口类】
    class CDisassembling 
    {
    public:
        CDisassembling();
        virtual ~CDisassembling();
        void UpdateDisassembling(ESubjectState e);
    };
    
    CDisassembling::CDisassembling(){}
    CDisassembling::~CDisassembling(){}
    void CDisassembling::UpdateDisassembling(ESubjectState e)
    {
        switch(e)
        {
        case  Start:
            cout<<"调试器启动了,展开 反汇编窗口 
    ";
            break;
        case End:
            cout<<"调试器关闭了,收起 反汇编窗口 
    ";
            break;
        default:
            break;
        }
    
    } 

     

     

     

    通知者类

     

    通知者抽象基类

    //【通知者】抽象类
    class CSubject
    {
    public:
        typedef std::function<void(ESubjectState)> PUpdateFunc;  
        typedef vector<PUpdateFunc> PTRVEC; 
    
        CSubject();
        virtual ~CSubject();
        virtual void AddObserer(PUpdateFunc pFunc)     = 0;  //添加观察者
        virtual void RemoveObserver(PUpdateFunc pFunc) = 0;  //删除观察者
        virtual void Notify(ESubjectState e)           = 0;  //通知函数
    
    protected:
        PTRVEC    m_ptrArr; 
    };
    
    CSubject::CSubject(){}
    CSubject::~CSubject(){}

     

     

     

    具体通知者类:调试器类

    /**************************************
    和前一篇将的在使用std::function时的问题类似,这里在函数AddObsererstd中使用std::find函数和RemoveObserver函数中使用std::find函数和opeartor == 时都有问题。
     即暂时不能判断vector中没有待插入的函数时才插入, 也不能在删除观察者时查找到后再erase
    ***************************************/
    
    //【通知者】--【调试器类】
    class CDebugger : public CSubject
    {
    public:
        CDebugger();
        virtual ~CDebugger();
        virtual void AddObserer(PUpdateFunc pFunc);       //添加观察者
        virtual void RemoveObserver(PUpdateFunc pFunc);   //删除观察者
        virtual void Notify(ESubjectState e);             //通知函数
    };
    
    CDebugger::CDebugger(){}
    CDebugger::~CDebugger(){}
    
    //添加观察者,当待添加的观察者不存在时才添加
    void CDebugger::AddObserer(PUpdateFunc pFunc)
    {
        //if(find(m_ptrArr.begin(), m_ptrArr.end(), pFunc) == m_ptrArr.end())
            m_ptrArr.push_back(pFunc); 
    }
    
    //删除观察者, 暂时不能删除
    void CDebugger::RemoveObserver(PUpdateFunc pFunc)
    {  
       /* PTRVEC::iterator iter = find(m_ptrArr.begin(), m_ptrArr.end(), pFunc);
        if(m_ptrArr.end() != iter) m_ptrArr.erase(iter);*/
         
    
        /*for (PTRVEC::iterator iter = m_ptrArr.begin(); iter != m_ptrArr.end(); ++ iter)
        {
    
        } */
    }
    void CDebugger::Notify(ESubjectState e)
    {
        for (PTRVEC::iterator iter = m_ptrArr.begin(); iter != m_ptrArr.end(); ++ iter)
        { 
            (*iter)(e); 
        }  
    }

     

     

     

     

    客户端代码

    int _tmain(int argc, _TCHAR* argv[])
    {   
    
        //通知者
        CSubject* pSubject = new CDebugger();
    
        //三个观察者, 一个是输出窗口, 另外两个是反汇编窗口
        COutputWnd objOutPut;
        CDisassembling objDisassembling1;
        CDisassembling objDisassembling2;
    
        
        cout<<"-----------添加三个观察者------------"<<endl;
        CSubject::PUpdateFunc func1 = std::bind(&COutputWnd::UpdateOutWnd, &objOutPut, std::placeholders::_1);
        pSubject->AddObserer(func1); 
    
        
        CSubject::PUpdateFunc func2 = std::bind(&CDisassembling::UpdateDisassembling, &objDisassembling1, std::placeholders::_1);
        pSubject->AddObserer(func2);
    
        CSubject::PUpdateFunc func3 = std::bind(&CDisassembling::UpdateDisassembling, &objDisassembling2, std::placeholders::_1);
        pSubject->AddObserer(func3); 
    
    
        pSubject->Notify(Start); 
    
        cout<<endl;
    
        pSubject->Notify(End);
    
    
        cout<<endl<<"----------把观察者3删除-------------"<<endl;
        pSubject->RemoveObserver(func3);
        pSubject->Notify(Start);
        cout<<endl;
        pSubject->Notify(End);
    
        cout<<endl<<endl;
    
        delete pSubject; pSubject = NULL; 
    
        return 0;
    }

     

     

     

    运行结果

     

     

      

      

  • 相关阅读:
    NPOI Word 多级标题结构设置
    ^M的问题解决
    sed命令详解
    Python time datetime string 相互转换
    Linux环境下调试python代码----pdb模块
    k8s更新证书记录
    sealos + NFS 部署 kubesphere 3.0
    使用wireshark排除一例网络问题
    Prometheus监控Oracle数据库
    记录一次清理挖矿病毒
  • 原文地址:https://www.cnblogs.com/cuish/p/3801271.html
Copyright © 2011-2022 走看看