观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。
观察者
(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。观察者模式的作用是:当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
观察者模式有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或从属者模式。
我在面试的时候被问道观察者模式、MVC,结果没反应过来。
在PPTV被问道点击事件是怎么传给图形界面的,我也没理解他在问这个问题,后来才恍然大悟,估计被鄙视了。
这片文章也算是顺便证明一下我对设计模式的理解深度吧,我敢肯定的说,你们错过了一个C++高手。
在C++的许多库实现中、在MVC模型中、在博客订阅系统中,都使用了观察者模式。
对C++而言,这个模式最大的用处在于
为C++添加事件概念(比如C#就直接在语法层面提供了事件的概念),像 object-c和JAVA提供委托,也是为了支持事件机制。
在《UNIX编程艺术》中提到软件设计最重要的是正交,解耦。作为UNIX程序员我原本只知道这么告诉别人“数据与逻辑分离”、“将策略和机制分开”,后来应用程序界面设计者就是告诉我:这个东西是符合“Model-View-Control”的,然后我整理了一下才明白MVC也是观察者模式的一种机制.
好了,我们省事一点,改百度百科的代码吧。
原地址:
http://baike.baidu.com/view/1854779.htm业务逻辑是:在MVC中,
用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。
UML图如下:
观察者
(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
被观察
被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
撤销观察
观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。
C++代码:
//filename observer.h
#include <iostream>
#include <set>
#include <string>
using namespace std;
/////////////////////抽象模式定义
class CObservable;
//观察者,纯虚基类
class CObserver
{
public:
CObserver(){};
virtual ~CObserver(){};
//当被观察的目标发生变化时,通知调用该方法
//来自被观察者pObs, 扩展参数为pArg
virtual void Update(CObservable* pObs, void* pArg = NULL) = 0;
};
//被观察者,即Subject
class CObservable
{
public:
CObservable() : m_bChanged(false) {};
virtual ~CObservable() {};
void Attach(CObserver* pObs); //注册观察者
void Detach(CObserver* pObs); //注销观察者
void DetachAll(); //注销所有观察者
void Notify(void* pArg = NULL); //若状态变化,则遍历观察者,逐个通知更新
bool HasChanged(); //测试目标状态是否变化
int GetObserversCount(); //获取观察者数量
protected:
void SetChanged(); //设置状态变化!!!必须继承CObservable才能设置目标状态
void ClearChanged(); //初始化目标为未变化状态
private:
bool m_bChanged; //状态
set<CObserver*> m_setObs; //set保证目标唯一性
};
/////////////////////抽象模式实现
void CObservable::Attach(CObserver* pObs){
if (!pObs) return;
m_setObs.insert(pObs);
}
void CObservable::Detach(CObserver* pObs){
if (!pObs) return;
m_setObs.erase(pObs);
}
void CObservable::DetachAll(){
m_setObs.clear();
}
void CObservable::SetChanged(){
m_bChanged = true;
}
void CObservable::ClearChanged(){
m_bChanged = false;
}
bool CObservable::HasChanged(){
return m_bChanged;
}
int CObservable::GetObserversCount(){
return m_setObs.size();
}
void CObservable::Notify(void* pArg /* = NULL */){
if (!HasChanged()) return;
cout << "notify observers…" << endl;
ClearChanged();
set<CObserver*>::iterator itr = m_setObs.begin();
for (; itr != m_setObs.end(); itr++){
(*itr)->Update(this, pArg);
}
}
/////////////////////具体应用类定义和实现
//bloger是发布者,即被观察者(subject)
class CBloger : public CObservable
{
public:
void Publish(const string &strContent){
cout << "bloger publish, content: " << strContent << endl;
SetChanged();
Notify(const_cast<char*>(strContent.c_str()));
}
};
//portal是发布者,即被观察者(subject)
class CPortal : public CObservable
{
public:
void Publish(const string &strContent){
cout << "portal publish, content: " << strContent << endl;
SetChanged();
Notify(const_cast<char*>(strContent.c_str()));
}
};
//RSS阅读器,观察者
class CRSSReader : public CObserver
{
public:
CRSSReader(const string &strName) : m_strName(strName){}
virtual void Update(CObservable* pObs, void* pArg = NULL){
char* pContent = static_cast<char*>(pArg);
//观察多个目标
if (dynamic_cast<CBloger*>(pObs)){
cout << m_strName << " updated from bloger, content: " << pContent << endl;
}else if (dynamic_cast<CPortal*>(pObs)){
cout << m_strName << " updated from portal, content: " << pContent << endl;
}
}
private:
string m_strName;
};
//Mail阅读器,观察者
class CMailReader : public CObserver
{
public:
CMailReader(const string &strName) : m_strName(strName){}
virtual void Update(CObservable* pObs, void* pArg = NULL){
char* pContent = static_cast<char*>(pArg);
if (dynamic_cast<CBloger*>(pObs)){
cout << m_strName << " updated from bloger, content: " << pContent << endl;
}
if (dynamic_cast<CPortal*>(pObs)){
cout << m_strName << " updated from portal, content: " << pContent << endl;
}
}
private:
string m_strName;
};
测试用例:
#include "observer.h"
int main()
{
//目标(被观察者)
CBloger* pBloger = new CBloger();
CPortal* pPortal = new CPortal();
//观察者. 一个观察者可以观察多个目标
CRSSReader* pRssReader = new CRSSReader("rss reader");
CMailReader* pMailReader = new CMailReader("mail reader");
pBloger->Attach(pRssReader); //bloger注册观察者
pBloger->Attach(pMailReader); //bloger注册观察者
pPortal->Attach(pRssReader); //portal注册观察者
pPortal->Attach(pMailReader); //portal注册观察者
//博客发布信息
pBloger->Publish("博客分享设计模式");
cout << endl;
//门户发布信息
pPortal->Publish("门户分享设计模式");
cout << "\nportal detached mail reader" << endl;
pPortal->Detach(pMailReader);
cout << "portal observers count: " << pPortal->GetObserversCount() << endl << endl;
pPortal->Publish("门户分享设计模式");
system("pause");
return 0;
}