1.观察者模式 Observer
首先根据字面意思肯定知道有 观察者 和 被观察者。 根据模式规定,这是一个一对多的依赖关系。
当被观察者更新状态,并且发出通知 观察者,观察者做出相对应的动作。这个前提是观察者关注了他所需要的内容。
比如:
a. 移动公司调整套餐资费,发出短信告诉你最新资费,你使用手机查看新的内容(或许你就要变更资费了)。此时移动公司是被观察者,你是观察者。
b. 你关注了人民日报公众号,人民日报在公众号发布,明天收复菲律宾,让他回到祖国的怀抱,你拿起手机根据内容,定了一张明天飞往南沙群岛的几篇,准备看风景。
总的来说
2. 一个错误例子的分析
背景:被观察者:papi酱 ; 观察者:小A, 小B, 小C
主题:直播
7月17日,papi酱 更新状态 下午 4点 直播,小A,小B,小C同时关注Papi酱,都收到了消息,表示会看直播。
伪代码:
class Papi酱;
public :
void 直播InfoChanged() {
QString strInfo = get直播Info();
小A.update( strInfo ); //收到通知,去看直播
小B.update( strInfo ); //收到通知,去看直播
小C.update( strInfo ); //收到通知,去看直播 // 果断不喜欢了,这里还得再Papi酱的代码手动去掉
}
如果这么写的话,我们可以达到目的,但是过了段时间
小C不再喜欢看Papi酱的直播了,还得Papi酱手动修改自己维护列表(代码),把小C去掉,传说中Papi酱有2000万粉丝啊,那不把她累死了。
这个例子就是类之间的调用,直接紧密的耦合起来了。 从根本上违反了面向对象的设计原则。
那么我们怎么做才好呢?
比较直观的一种是使用一种“注册——通知——撤销注册”的形式
(上图假设 小A、小B、小C只关注了Papi酱,没人关注习大大,当然你可以让小A、小B同时也关注老习)
3. 下来看看代码:
观察者接口 : QObserver
被观察者接口:QObservable
QObserver.h
#ifndef QOBSERVER
#define QOBSERVER
#include // .h不认识NULL所以加了 这个头文件
class QObservable;
class QObserver
{
public:
virtual ~QObserver()
{
}
//当被观察的目标发生变化时,通知调用该方法
//来自被观察者pObs,扩展参数为pArg
virtual void Update(QObservable *pObs, void *pArg = NULL) = 0;
};
#endif // QOBSERVER
QObservable.h
#ifndef QOBSERVABLE_H
#define QOBSERVABLE_H
#include "QObserver.h"
#include
class QObservable
{
public:
QObservable();
virtual ~QObservable(){}
// 注册观察者
void Attach(QObserver *pObs);
// 注销观察者
void Detach(QObserver *pObs);
// 注销所有观察者
void DetachAll();
// 若状态变化,则遍历所有观察者,逐个通知更新
void Notify(void *pArg = NULL);
// 测试目标状态是否变化
bool HasChanged();
// 获取观察者数量
int GetObserversCount();
protected:
// 设置状态变化!!!必须继承QObervable才能设置目标状态
void SetChanged();
// 初始化目标为未变化状态
void ClearChanged();
private:
// 状态
bool m_bChanged;
// set保证目标唯一性
QSet m_setObs;
};
#endif // QOBSERVABLE_H
QObservable.cpp
#include "QObservable.h"
#include
QObservable::QObservable():m_bChanged(false)
{
}
void QObservable::Attach(QObserver *pObs)
{
if(!pObs)
return;
m_setObs.insert(pObs);
}
void QObservable::Detach(QObserver *pObs)
{
if(!pObs)
return;
m_setObs.remove(pObs);
}
void QObservable::DetachAll()
{
m_setObs.clear();
}
void QObservable::Notify(void *pArg)
{
if(!HasChanged())
return;
qDebug() << "notify observers…" ;
ClearChanged();
QSet::iterator itr = m_setObs.begin();
for(; itr != m_setObs.end(); itr++)
{
(*itr)->Update(this,pArg);
}
}
bool QObservable::HasChanged()
{
return m_bChanged;
}
int QObservable::GetObserversCount()
{
return m_setObs.size();
}
void QObservable::SetChanged()
{
m_bChanged=true;
}
void QObservable::ClearChanged()
{
m_bChanged=false;
}
观察者主要是获取信息(获取信息前提是已经是注册会员了);
被观察者 自身信息变化了才更新,同时用户在我这里注册了才给对应用户更新。
好了
Papi酱和习大大都是被观察的人啊。(这边简单起来就只写Papi酱了,多(观察者)对多(被观察者)和 一对多是一个道理)
QPapi.h
#ifndef QPAPI_H
#define QPAPI_H
#include "QObservable.h" // 头文件还是得添加下
class QPapi : public QObservable
{
public:
QPapi();
void Zhibo(const QString &strContent);
};
#endif // QPAPI_H
#include "QPapi.h"
#include
QPapi::QPapi()
{
}
void QPapi::Zhibo(const QString &strContent)
{
qDebug() << "Papi says:" << strContent;
SetChanged();
Notify(const_cast(strContent.toStdString().c_str()));
}
(观察者)小A,小B要上场了。记得要继承接口QObserver
小A.h
#ifndef SMALLA_H
#define SMALLA_H
#include "QObserver.h"
#include "QObservable.h"
#include "QPapi.h"
#include
class SmallA : public QObserver
{
public:
SmallA(const QString &strName);
virtual void Update(QObservable *pObs, void *pArg);
private:
QString m_strName;
};
#endif // SMALLA_H
#include "SmallA.h"
#include
SmallA::SmallA(const QString &strName)
:m_strName(strName)
{
}
void SmallA::Update(QObservable *pObs, void *pArg)
{
char *pContent = static_cast(pArg);
// 观察目标
if(dynamic_cast (pObs))
{
qDebug() << m_strName << "I know Papi:" << pContent;
}
else
{
}
}
好了,所有成员到齐了。
下来我们准备运行我们的模式吧。
main.cpp
#include
#include
#include "SmallA.h"
#include "SmallB.h"
#include "QPapi.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 目标(被观察者)
QPapi * pPapi = new QPapi();
// 观察者 小A 小B
SmallA * smallA = new SmallA("Small A");
SmallB * smallB = new SmallB("Small B");
// 小A 小B 都仰慕 Papi酱 并且注册成员粉丝
pPapi->Attach(smallA);
pPapi->Attach(smallB);
// Papi酱de粉丝
qDebug() <<"fensi:"<< pPapi->GetObserversCount();
// Papi酱说我要直播啦
pPapi->Zhibo("4am zhibo");
// 过了一段日子 小A对Papi酱没兴趣了,取消关注
pPapi->Detach((smallA));
// 看下Papi酱还有多少粉丝
qDebug() <<"fensi:"<< pPapi->GetObserversCount();
// Papi酱又要直播啦
pPapi->Zhibo("8am zhibo");
return a.exec();
}
大概介绍完了,看下 Head Firse设计模式 and 百度百科 就会明白,我是两个都看了遍才明白的。
自己又顺着思路写了下,希望能帮助你。