码迷,mamicode.com
首页 > 其他好文 > 详细

observer(观察者模式)

时间:2015-07-14 17:57:27      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:

有这么一种松耦合的需求:

有一些类的对象对类A对象的状态变化很感兴趣,不会改变类A的对象,也不会被类A的对象改变,想以一种较小的代价观察对类A对象状态变化。

下面的几种方式也能实现上述目的

(1)通过类的继承来共同管理和维护一些感兴趣的数据或者状态,但是耦合度大,不易扩展和维护。

(2)通过调用被观察者的getter方法获取数据,这个还是直接的对象调用。

上述两种方法将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,

还是被观察者将自己的改变“通知”观察者,都不应该直接调用。


观察者模式(有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或从属者模式)中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。陈硕的《linux多线程服务端编程 使用muduo c+网络库》中有一个多人聊天的例子,在服务端程序中,要把一个客户端发来的消息分发给所有的客户端,也可以看待是观察者模式的典型案例,TCP的连接视为注册,消息的分发视为通知,TCP连接的断开视为撤销注册。

技术分享

观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
被观察

被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
撤销观察

观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。

C++例子

#include<iostream>
#include<set>
#include<string>
usingnamespacestd;
/////////////////////抽象模式定义
classCObservable;
//观察者,纯虚基类
classCObserver
{
public:
CObserver::CObserver(){};
virtualCObserver::~CObserver(){};
//当被观察的目标发生变化时,通知调用该方法
//来自被观察者pObs,扩展参数为pArg
virtualvoidUpdate(CObservable*pObs,void*pArg=NULL)=0;
};
//被观察者,即Subject
classCObservable
{
public:
CObservable():m_bChanged(false){};
virtual~CObservable(){};
//注册观察者
voidAttach(CObserver*pObs);
//注销观察者
voidDetach(CObserver*pObs);
//注销所有观察者
voidDetachAll();
//若状态变化,则遍历观察者,逐个通知更新
voidNotify(void*pArg=NULL);
//测试目标状态是否变化
boolHasChanged();
//获取观察者数量
intGetObserversCount();
protected:
//设置状态变化!!!必须继承CObservable才能设置目标状态
voidSetChanged();
//初始化目标为未变化状态
voidClearChanged();
private:
boolm_bChanged;//状态
set<CObserver*>m_setObs;//set保证目标唯一性
};
/////////////////////抽象模式实现
voidCObservable::Attach(CObserver*pObs)
{
if(!pObs)return;
m_setObs.insert(pObs);
}
voidCObservable::Detach(CObserver*pObs)
{
if(!pObs)return;
m_setObs.erase(pObs);
}
voidCObservable::DetachAll()
{
m_setObs.clear();
}
voidCObservable::SetChanged()
{
m_bChanged=true;
}
voidCObservable::ClearChanged()
{
m_bChanged=false;
}
boolCObservable::HasChanged()
{
returnm_bChanged;
}
intCObservable::GetObserversCount()
{
returnm_setObs.size();
}
voidCObservable::Notify(void*pArg/*=NULL*/)
{
if(!HasChanged())return;
cout<<"notifyobservers…"<<endl;
ClearChanged();
set<CObserver*>::iteratoritr=m_setObs.begin();
for(;itr!=m_setObs.end();itr++)
{
(*itr)->Update(this,pArg);
}
}
/////////////////////具体应用类定义和实现
//bloger是发布者,即被观察者(subject)
classCBloger:publicCObservable
{
public:
voidPublish(conststring&strContent)
{
cout<<"blogerpublish,content:"<<strContent<<endl;
SetChanged();
Notify(const_cast<char*>(strContent.c_str()));
}
};
//portal是发布者,即被观察者(subject)
classCPortal:publicCObservable
{
public:
voidPublish(conststring&strContent)
{
cout<<"portalpublish,content:"<<strContent<<endl;
SetChanged();
Notify(const_cast<char*>(strContent.c_str()));
}
};
//RSS阅读器,观察者
classCRSSReader:publicCObserver
{
public:
CRSSReader(conststring&strName):m_strName(strName){}
virtualvoidUpdate(CObservable*pObs,void*pArg=NULL)
{
char*pContent=static_cast<char*>(pArg);
//观察多个目标
if(dynamic_cast<CBloger*>(pObs))
{
cout<<m_strName<<"updatedfrombloger,content:"<<pContent<<endl;
}
elseif(dynamic_cast<CPortal*>(pObs))
{
cout<<m_strName<<"updatedfromportal,content:"<<pContent<<endl;
}
}
private:
stringm_strName;
};
//Mail阅读器,观察者
classCMailReader:publicCObserver
{
public:
CMailReader(conststring&strName):m_strName(strName){}
virtualvoidUpdate(CObservable*pObs,void*pArg=NULL)
{
char*pContent=static_cast<char*>(pArg);
if(dynamic_cast<CBloger*>(pObs))
{
cout<<m_strName<<"updatedfrombloger,content:"<<pContent<<endl;
}
if(dynamic_cast<CPortal*>(pObs))
{
cout<<m_strName<<"updatedfromportal,content:"<<pContent<<endl;
}
}
private:
stringm_strName;
};
/////////////////Main
intmain()
{
//目标(被观察者)
CBloger*pBloger=newCBloger();
CPortal*pPortal=newCPortal();
//观察者.一个观察者可以观察多个目标
CRSSReader*pRssReader=newCRSSReader("rssreader");
CMailReader*pMailReader=newCMailReader("mailreader");
pBloger->Attach(pRssReader);//bloger注册观察者
pBloger->Attach(pMailReader);//bloger注册观察者
pPortal->Attach(pRssReader);//portal注册观察者
pPortal->Attach(pMailReader);//portal注册观察者
//博客发布信息
pBloger->Publish("博客分享设计模式");
cout<<endl;
//门户发布信息
pPortal->Publish("门户分享设计模式");
cout<<"\nportaldetachedmailreader"<<endl;
pPortal->Detach(pMailReader);
cout<<"portalobserverscount:"<<pPortal->GetObserversCount()<<endl<<endl;
pPortal->Publish("门户分享设计模式");
system("pause");
return0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

observer(观察者模式)

标签:

原文地址:http://blog.csdn.net/hustyangju/article/details/46881065

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!