zoukankan      html  css  js  c++  java
  • 【设计模式】观察者模式

     

     

    观察者模式

    适用于一个变化会引起其他多个变化

    引起变化的叫【通知者】,被引起变化的叫【观察者】。 

    从代码实现角度讲,【抽象通知者】需要依赖于【抽象观察者】,至少需要知道抽象观察者的类名和一个【更新函数】名。

    这个模式的一般实现有点违反【面向接口编程,不要面向实现编程】,而且观察者的更新函数是同一个抽象基类的虚函数,其函数名相同(功能也是类似的功能),而不是每个观察者有不同的动作(即不必都是相同的【更新函数】)。

    C#为了解决此问题,使用了在【观察者】中不用继承结构,使用委托和事件来实现,即不同的观察者中的【更新函数】各自不同,而使用委托和事件,

    delegate  int  UpdateFunc(int);

    UpdateFunc  func += new EventHandler(不同具体观察者的同原型的更新函数)

     在C++中在解决这个问题呢?  需要解决一个问题(没有继承结构的前提下):C#中的委托类似于C++中的函数指针,而C++中的类成员函数指针在不同类之间的转换有问题? 点解决?

    /************************************************************************/
    /* 设计模式
       观察者模式
    
       若干个【通知者】,若干个【观察者】
       【通知者】可以向【观察者】发出通知,以便让【观察者】的状态发生变化。
       【通知者】可以增减他的【观察者】,这样有一个缺点就是违反了依赖倒转原则,
       【通知者】依赖于【观察者】,即【通知者】至少需要知道【观察者】的名字和
       更新【观察者】状态的“方法”。 
    
       以【大话设计模式】里的讲到的Visual Studio的窗口变化为例: 
       当【启动调试】时,【输出】窗口展开,【反汇编】窗口展开
       当【结束调试】时,【输出】窗口隐藏,【反汇编】窗口隐藏
       所以这里的【通知者】为【调试器】,【观察者】为【输出】和【反汇编】窗口
    /************************************************************************/

     

     调试器的两个动作:启动调试 和 停止调试

    //调试器的两个行为:启动 和 停止
    typedef enum _ESubjectState{Start = 0, End = 1}ESubjectState;

    观察者抽象基类,窗口

    //【观察者】--【窗口类】
    class CWindow
    {
    public:
        CWindow();
        virtual ~CWindow();
        virtual void Update(ESubjectState e) = 0;  //更新状态的虚函数
    };
    
    CWindow::CWindow(){}
    CWindow::~CWindow(){}
    
    //////////////////////////////////////////////////////////////////////////

     

    第一个具体观察者类, 输出窗口类

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

    第二个具体观察者,反汇编窗口类

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

    ------------------------------------------------------------------------------------------------

    通知者抽象类, 主题类

    //【通知者】抽象类
    class CSubject
    {
    public:
        CSubject();
        virtual ~CSubject();
        virtual void AddObserer(CWindow* pWnd)     = 0;  //添加观察者
        virtual void RemoveObserver(CWindow* pWnd) = 0;  //删除观察者
        virtual void Notify(ESubjectState e)       = 0;  //通知函数
    
    protected:
        typedef vector<CWindow*> ObserverWnd;
        ObserverWnd m_vecObserver; 
    };
    
    CSubject::CSubject(){}
    CSubject::~CSubject(){}

    一个具体的通知者类, 调试器类

    //【通知者】--【调试器类】
    class CDebugger : public CSubject
    {
    public:
        CDebugger();
        virtual ~CDebugger();
        virtual void AddObserer(CWindow* pWnd);       //添加观察者
        virtual void RemoveObserver(CWindow* pWnd);   //删除观察者
        virtual void Notify(ESubjectState e);         //通知函数
    };
    
    CDebugger::CDebugger(){}
    CDebugger::~CDebugger(){}
    
    //添加观察者,当待添加的观察者不存在时才添加
    void CDebugger::AddObserer(CWindow* pWnd)
    {
        if(find(m_vecObserver.begin(), m_vecObserver.end(), pWnd) == m_vecObserver.end())
            m_vecObserver.push_back(pWnd);
    }
    
    //删除观察者
    void CDebugger::RemoveObserver(CWindow* pWnd)
    {  
        ObserverWnd::iterator iter = find(m_vecObserver.begin(), m_vecObserver.end(), pWnd);
        if(m_vecObserver.end() != iter) m_vecObserver.erase(iter);
    }
    void CDebugger::Notify(ESubjectState e)
    {
        for (ObserverWnd::iterator iter = m_vecObserver.begin(); iter != m_vecObserver.end(); ++ iter)
        { 
            (*iter)->Update(e); 
        }  
    }

    客户端代码

    int _tmain(int argc, _TCHAR* argv[])
    {  
    
        //通知者
        CSubject* pSubject = new CDebugger();
        
        //三个观察者, 一个是输出窗口, 另外两个是反汇编窗口
        CWindow* pWnd1 = new COutputWnd();
        CWindow* pWnd2 = new CDisassembling();
        CWindow* pWnd3 = new CDisassembling();
    
        cout<<"-----------添加三个观察者------------"<<endl;
        pSubject->AddObserer(pWnd1);
        pSubject->AddObserer(pWnd2);
        pSubject->AddObserer(pWnd3);
        pSubject->Notify(Start);
    
        cout<<endl;
    
        pSubject->Notify(End);
    
    
        cout<<endl<<"----------把观察者3删除-------------"<<endl;
        pSubject->RemoveObserver(pWnd3);
        pSubject->Notify(Start);
        cout<<endl;
        pSubject->Notify(End);
    
        cout<<endl<<endl;
    
        delete pSubject; pSubject = NULL;
        delete pWnd1;    pWnd1    = NULL;
        delete pWnd2;    pWnd2    = NULL;
        delete pWnd3;    pWnd3    = NULL;
    
        return 0;
    }

     

  • 相关阅读:
    【代码沉淀】
    【整理总结】目录
    Windows service installer with InstallShield LE
    (The application/json Media Type for JavaScript Object Notation (JSON))RFC4627-JSON格式定义
    Microsoft .NET Framework 4 安装 1603错误的解决
    SQL SERVER 无法正常连接的那些事
    【整理总结】我的装机软件以及说明
    Wcf服务测试自带工具
    Postgresql 远程连接配置
    Caliburn.Micro
  • 原文地址:https://www.cnblogs.com/cuish/p/3801044.html
Copyright © 2011-2022 走看看