设为首页 加入收藏

TOP

C++屌屌的观察者模式-同步回调和异步回调(一)
2019-07-10 08:09:22 】 浏览:160
Tags:观察者 模式 同步 调和 异步

原文链接:C++屌屌的观察者模式-同步回调和异步回调

一、概述

说起观察者模式,也是比较简单的一种模式了,稍微工作有1年经验的同学,写起来都是666...

想看观察者模式的说明可以直接上菜鸟教程|观察者模式这个地址去看。

本篇文章其实就是一个简单的观察者模式,只是使用了模板的方式,把我们的回调接口进行了参数化,这样有什么好处呢?

好处当然是大大的有了。 平时我们在不同业务逻辑之间写观察者模式呢,都得写好多个,大家有没有发现,所有的被观察者Subject其实很多操作都是一样的。

本篇我们带来两种观察者模式:同步观察者和异步观察者

1、同步观察者

顾名思义,同步观察者其实就是不管是谁,触发了Subject的Update操作,该操作都是同步进行的,他会调用所有的观察者(Observer)的OnUpdate接口,来通知Observer处理改变操作。

如效果展示图中的第一个单次拉取页签,当我们点击拉取按钮时,就相当于触发了一次Subject对象的Update操作

2、异步观察者

异步观察者模式上和同步观察者基本一样,只是在事件处理上有稍微不同

  1. 执行Update操作是由Subject自己去完成的
  2. 调用Observer的OnUpdate回调接口时,处于工作线程中
  3. Subject所有的请求操作都是在工作现场中进行

如效果图所示,定时拉取观察者模式,Subject启动了一个后台线程,3秒钟拉取一次数据,并回调到界面

二、效果展示

如下图所示,是一个简单的观察者模式事例。

单次拉取:演示了同步观察者模式

定时拉取:演示了异步观察者模式

工程结构如图所示,这里只把头文件的目录展示出来了。

实现文件的目录和头文件类似,为了截图方便所以做了隐藏操作。

Header Files目录下有2个虚拟文件夹,分别就是对单次拉取定时拉取功能的实践

下面我们就来正式开始讲解这个屌屌的观察者模式

三、同步观察者

1、首先就是定义一堆接口和回调参数

struct DataItem
{
    std::string     strID;  
    std::string     strName;        
};

typedef IUpdate1<DataItem>          ISignalObserver;

//单次回调
struct ISignal : public SubjectBase<ISignalObserver>
{
    virtual void RequestData() = 0;
};

2、业务观察者

这里我定义了一个SignalResponse业务观察者,也就是我们在开发工程中的实际功能类。

class SignalResponse : public ISignal
{
public:
    SignalResponse();
    ~SignalResponse();

public:
    virtual void RequestData() override;

private:
    
};

*3、获取观察者指针**

通过一个门面接口获取观察者指针

  1. 调用ISignal的Attach接口,就可以把自己添加到观察者列表。
  2. 调用ISignal的RequestData接口,就可以拉取数据。
  3. 调用ISignal的Detach接口,就可以把自己从观察者列表中移除。
ISignal * GetSignalCommon();

4、UI界面

接下来就是写一个UI界面啦,当我们通过上一步调用拉取数据接口后,我们的UI上相应的OnUpdate接口就会被回调

class SignalWidget : public QWidget, public ISignalObserver
{
    Q_OBJECT

public:
    SignalWidget(QWidget * parent = 0);
    ~SignalWidget();

protected:
    virtual void OnUpdate(const DataItem &) override;

private slots:
    void on_pushButton_clicked();

private:
    Ui::SignalWidget *ui;
};

通过以上四步,就可以很方便的实现一个现在业务中的观察者,是不是很简单呢,编写过程中,需要完成这几个地方

  1. 需要定义我们回调函数的参数结构
  2. 需要实例化一个被观察者接口类
  3. 实例化一个业务观察者
  4. 做一个UI界面,并集成第二步实例化的被观察者的模板参数(接口类)

注意看这里的ISignalObserver,是不是很眼熟,其实他就是我们的模板被观察者SubjectBase的模板参数。

讲到这里,大家是不是都很关心这个模板观察者到底是何方神圣,居然这么叼。那么接下来就是模板SubjectBase出场啦。。。

下面我直接给出代码,学过C++的同学阅读起来应该都不难。

觉着难了就多读几遍

template <typename T>
struct ISubject
{
    virtual void Attach(T * pObserver) = 0;
    virtual void Detach(T * pObserver) = 0;
};

template <typename P>
struct IUpdate1
{
    virtual void OnUpdate(const P& data) = 0;
};

template <typename P1, typename P2>
struct IUpdate2
{
    virtual void OnUpdate2(const P1 & p1, const P2 & p2) = 0;
};

template <typename P>
struct IUpdate1_P
{
    virtual void OnUpdate(const P * data) = 0;
};

template <typename T>
struct SubjectBase
{
public:
    virtual void Attach(T * pObserver)
    {
        std::lock_guard<std::mutex> lg(m_mutex);
#ifdef _DEBUG
        if (m_observers.end() != std::find(m_observers.begin(), m_observers.end(), pObserver))
        {
            assert(false);
        }
#endif // _DEBUG
        m_observers.push_back(pObserver);
    }

    virtual void Detach(T * pObserver)
    {
        std::lock_guard<std::mutex> lg(m_mutex);
        auto it = std::find(m_observers.begin(), m_observers.end(), pObserver);
        if (it != m_observers.end())
        {
            m_observers.erase(it);
        }
        else
        {
            assert(false);
        }
    }

    //prot
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Can you answer these queries III 下一篇基数排序的可复用实现(C++11/14/..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目