【设计模式】观察者模式(改进后的)

 

前言

之前  观察者模式一篇 中,【通知者】需要知道【观察者】的类名和更新函数名,耦合度稍大,本篇稍稍修改一下,类似于大话设计模式里的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;
}

 

 

 

运行结果

 

 

  

  

原文地址:https://www.cnblogs.com/cuish/p/3801271.html