Qt-观察者模式

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

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

时间: 2024-08-10 21:25:31

Qt-观察者模式的相关文章

[设计模式]&lt;9&gt;. C++与观察者模式(observer pattern)

作者:默默地EEer 原文:http://www.cnblogs.com/hebaichuanyeah/p/6091694.html 意图: 定义对象间一对多的依赖关系,使得一个对象被改变,其他对象被更新. java的事件机制就是一个观察者模式,当事件发生,所有的事件接收者执行事件响应函数. 实现观察者模式,首先需要定义一个"观察者类(observer)"接口,在该类里面定义一个纯虚的事件响应函数. 并且需要一个"目标类(subject)",该类里面包含一个Set/

如何才能学到Qt的精髓

姚冬,中老年程序员 叶韵.KY Xu.赵奋强 等人赞同 被邀请了很久了,一直在思考,今天终于下决心开始写回答. 这个问题的确是够大的,Qt的代码规模在整个开源世界里也是名列前茅的,这么大的项目其中的精华是非常多的,很难说得全面,实际上我对Qt也不是完全了解,里面还有很多我不熟悉的东西. 首先,我想谈的是 signal/slot,Qt算是发明了signal/slot,这个思想也被其他一些框架语言借鉴了. 谈signal/slot之前先来谈谈C++的缺欠,这个问题也被讨论很多了,这里只谈一点,C++

Qt 学习之路 2 --- 读书笔记

一.文章来由 来自豆子老师非常好的一本Qt教程,但是只有网络版,所以用这个做笔记了,不动笔墨不读书嘛~~ 二.读书笔记 1.Qt 学习之路 2(2):Qt 简介 1.1 关于 Qt 的一站式解决 Qt 是一个著名的 C++ 应用程序框架.但并不只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件.使用 Qt,在一定程度上你获得的是一个"一站式"的解决方案:不再需要研究 STL,不再需要 C++ 的,不再需要到处去找解析 XML.连接数据库.访问网络的各种第三方库,因为

[设计模式]_[观察者模式在项目中实际使用例子]

场景: 1. 比如在界面开发中,多个窗口之间需要通讯,比较常见的方法就是各个窗口之间包含对其他窗口的引用,之后在需要时通过其他窗口的引用来调用相应的函数获取相应的值: 但是这个确定还是比较明显的,就是会造成窗口之间的依赖和耦合,想想测试或变异某个窗口时另一个窗口必须是没问题的,而另一个窗口编译又依赖它,这样成了反复依赖 导致编译不过或修改其中一个另一个就得相应的该.很麻烦,不好维护. 2. 还有的不切实际的解决办法是在窗口之间发送事件,比如qt得信号或win32的消息,但是这样会造成消息的泛滥,

Qt 学习之路 :信号槽

信号槽是 Qt 框架引以为豪的机制之一.熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力. 所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal).这种发出是没有目的的,类似广播.如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号.也就是说,当信号发出时,被连接的槽函数会自动被回调.这就类似观察者模式:当发生了感兴趣的事件

Qt学习六 - 信号与槽

一.简介 信号和槽是Qt的核心特征.用于对象间的通信,类似观察者模式.例如当一个按钮被点击,按钮监测到自己被点击了一下,就会发送一个信号(signal).这个信号无目的,类似广播.如果我们需要处理这个信号,那么就需要使用connect来连接一个对象,使用该对象对应的槽函数(slot)来处理这个信号.也就是说,当点击按钮时,会触发与之相关联的槽函数.一个信号可以关联多个槽函数,多个信号也可以关联到一个槽函数上,甚至一个信号还可以关联到另一个信号上.当信号被发射时,这些关联的槽会一个接一个的执行,但

Qt高级——Qt信号槽机制源码解析

Qt高级--Qt信号槽机制源码解析 基于Qt4.8.6版本 一.信号槽机制的原理 1.信号槽简介 信号槽是观察者模式的一种实现,特性如下:A.一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知:B.一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候--也可以说是信号发出的时候--被调用的函数:C.信号与槽的连接,形成一种观察者-被观察者的关系:D.当事件或者状态发生改变的时候,信号就会被发出:同时,信号发出者有义务调用所有注册的对这个事件(信号)感兴趣的函数(槽).信号和

Android中的设计模式之观察者模式

参考 <设计模式:可复用面向对象软件的基础 >5.7 Observer 观察者 对象行为型模式 <设计模式解析> 18.4 Observer模式 <Android源码设计模式解析与实战>第12章 解决,解耦的钥匙--观察者模式 本人能力有限,如有明显错误,不规范的地方,请指正,谢谢. 意图 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新. 别名 依赖(Dependents)发布-订阅(Publish-Subscrib

Qt信号槽机制源码解析

Qt信号槽机制源码解析 来源 https://blog.51cto.com/9291927/2070398 一.信号槽机制的原理 1.信号槽简介 信号槽是观察者模式的一种实现,特性如下:A.一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知:B.一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候——也可以说是信号发出的时候——被调用的函数:C.信号与槽的连接,形成一种观察者-被观察者的关系:D.当事件或者状态发生改变的时候,信号就会被发出:同时,信号发出者有义务调用所有注

Qt编译好的OCI驱动下载

在上文,我累赘了一大堆,给大家写了一篇Qt如何编译OCI驱动,在这里自然就不再累赘了,直接附上编译好的文件供大家下载: <Qt5.3.1+OCI驱动下载地址> 有经济来源的请传送:http://download.csdn.net/detail/u012433546/9922424 无经济来源的请传送:链接:http://pan.baidu.com/s/1boKG9lH 密码:7yj5 <Qt5.3.2+OCI驱动下载地址> 有经济来源的请传送:http://download.csd