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

Qt-观察者模式

时间:2016-07-17 16:08:00      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:


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

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

Qt-观察者模式

标签:

原文地址:http://blog.csdn.net/c3060911030/article/details/51928761

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