前言
之前 中,【通知者】需要知道【观察者】的类名和更新函数名,耦合度稍大,本篇稍稍修改一下,类似于大话设计模式里的C#描述的委托事件的方法。
采用 的方式,把每个【观察者】类的 相同原型的更新函数 指针转换为std::function然后保存起来。
然后在【通知者】的 通知函数 中调用保存起来的每个 【观察者】的更新函数。
本文去除了【观察者】的继承结构,【通知者】只需要知道每个【观察者】的更新函数原型。
去除了继承结构,因此每个【观察者】的更新函数也就不必是virtual的了。
描述
/************************************************************************//* 设计模式 观察者模式 本文介绍一种解耦的方法,使【通知者】不依赖于【观察者】 即【通知者】不知道【观察者】的太多细节,只需要知道【观察者】 的【更新函数原型】,所以这就要求【观察者】的更新函数的原型 要一致。 以【大话设计模式】里的讲到的Visual Studio的窗口变化为例: 当【启动调试】时,【输出】窗口展开,【反汇编】窗口展开 当【结束调试】时,【输出】窗口隐藏,【反汇编】窗口隐藏 所以这里的【通知者】为【调试器】,【观察者】为【输出】和【反汇编】窗口/************************************************************************/ //调试器的两个行为:启动 和 停止typedef enum _ESubjectState{Start = 0, End = 1}ESubjectState;
所需头文件
#include "stdafx.h"#include#include #include #include
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<<"调试器启动了,展开 输出窗口 \n"; break; case End: cout<<"调试器关闭了,收起 输出窗口 \n"; 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<<"调试器启动了,展开 反汇编窗口 \n"; break; case End: cout<<"调试器关闭了,收起 反汇编窗口 \n"; break; default: break; }}
通知者类
通知者抽象基类
//【通知者】抽象类class CSubject{public: typedef std::functionPUpdateFunc; typedef vector 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<<"-----------添加三个观察者------------"<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< Notify(End); cout< <<"----------把观察者3删除-------------"< RemoveObserver(func3); pSubject->Notify(Start); cout< Notify(End); cout< <
运行结果