Qt-观察者模式

来源:互联网 发布:二代身份证相片 软件 编辑:程序博客网 时间:2024/04/30 17:29


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<span style="color:#5555ff;">#include</span><span style="color:#c0c0c0;"> </span><span style="color:#ff55ff;"><QObject> // .h不认识NULL所以加了 这个头文件</span>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 <QSet>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 <QObserver*> m_setObs;};#endif // QOBSERVABLE_H

QObservable.cpp

#include "QObservable.h"#include <QDebug>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<QObserver*>::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

QPapi.cpp

#include "QPapi.h"<span style="color:#5555ff;">#include</span><span style="color:#c0c0c0;"> </span><span style="color:#ff55ff;"><QDebug></span>QPapi::QPapi(){}void QPapi::Zhibo(const QString &strContent){    qDebug() << "Papi says:" << strContent;    SetChanged();    Notify(const_cast<char*>(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 <QString>class SmallA : public QObserver{public:    SmallA(const QString &strName);    virtual void Update(QObservable *pObs, void *pArg);private:    QString m_strName;};#endif // SMALLA_H

小A.cpp
#include "SmallA.h"#include <QDebug>SmallA::SmallA(const QString &strName)    :m_strName(strName){}void SmallA::Update(QObservable *pObs, void *pArg){    char *pContent = static_cast<char*>(pArg);    // 观察目标    if(dynamic_cast <QPapi*>(pObs))    {        qDebug() << m_strName << "I know Papi:" << pContent;    }    else    {    }}

小A和小B 没啥区别,也是这么写。

好了,所有成员到齐了。

下来我们准备运行我们的模式吧。

main.cpp

#include <QCoreApplication>#include <QDebug>#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百度百科 就会明白,我是两个都看了遍才明白的。

自己又顺着思路写了下,希望能帮助你。

3 0
原创粉丝点击