观察者模式
适用于一个变化会引起其他多个变化
引起变化的叫【通知者】,被引起变化的叫【观察者】。
从代码实现角度讲,【抽象通知者】需要依赖于【抽象观察者】,至少需要知道抽象观察者的类名和一个【更新函数】名。
这个模式的一般实现有点违反【面向接口编程,不要面向实现编程】,而且观察者的更新函数是同一个抽象基类的虚函数,其函数名相同(功能也是类似的功能),而不是每个观察者有不同的动作(即不必都是相同的【更新函数】)。
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;
}