Qt--通过观察者模式实现信号槽

前提:1.熟悉了观察者模式,不熟悉看这个观察者模式
2.了解Qt的信号和信号槽。
3.熟悉std::bind()来调用类的方法std::bind调用类方法
4.熟悉模板类的简单使用模板类做基类

1.Qt中的信号和信号槽

  • 在Qt中-----准备工作
    1.定义A对象, 定义A对象的信号signal-A
    2.定义B对象,定义B对象的slot函数
    3.connect函数:将A对象发出的signal-A, 和B对象执行的slot函数绑定起来。
  • 信号触发
    4.A发出信号signal-A
    5.B收到signal-A就会执行slot函数

2.本质的解析

3.connect函数执行的动作:其实就是一个B对象订阅signal-A的动作。
4.A发出信号:即代表一个广播的动作,但只有B对象会处理这个信号,因为B对象有订阅这个信号。
5.B收到信号的处理动作,即执行slot()函数

上面的三点加起来就是:消息的订阅,消息的发布,消息的处理。这就是一个观察者模式。

3.通过观察者模式实现信号槽

假设这样一个场景:猫和老鼠的tom和jerry
1.jerry看着tom.
2.tom叫
3.jerry跑
上面三个对应:订阅,发布,处理。即Qt 的connect(), emit ,slot函数

#include "Subject.h"
#include <functional>
#include <iostream>

using std::cout;
using std::endl;

class catObserver {
public:
    virtual void onPublish() = 0;
public:
    virtual ~catObserver() {} // 避免内存泄漏
};


class Jerry : public catObserver {
public:
    void onPublish() { // 3.jerry听到tom叫执行的动作
        Run();
    }  

private:
    void Run() {
        cout << "hear tom miao,jerry run" << endl;
    }
};

class Tom {
public:
    void subscribe(catObserver* observer) {
        // subscribe jerry
        obj_list.push_back(observer);
    }
    void publish() {
        cout << "tom miao" << endl;
        for (auto tmp: obj_list) {
            tmp->onPublish();
        }
    }

    // 
private:
    // subscriber list
    std::vector<catObserver* > obj_list;
};


int main()
{
    Tom tom;
    Jerry jerry;
    //1. jerry 看着tom
    tom.subscribe(&jerry);
    //2.tom 叫
    tom.publish();
    return 0;
}

//上面的代码简单的实现了:消息的订阅,发布,和处理。而QT的信号槽不过是观察者模式的升级。
QT的connect() -----------------观察者模式的订阅,把消息和处理函数绑定起来(通过catObserver的虚方法的实现)
QT的emit某个signal ----------观察者模式的消息发布
QT的信号槽函数---------------观察者模式的消息处理

简单的封装带有publish,subscribe的基类

// VistorMode.h
#include <vector>
#include <algorithm>


//一个带有订阅。发布的基础类
template <typename ObserverType>
class Subject
{
public:
    // void subscribe(catObserver* observer)
/*希望subscribe的传参是任何类型的观察者,所以不能是catObserver,
希望在不同的子类定义的时候去定义子类,比如猫tom就应该传入catObserver
比如狗dog就该传入dogObserver,所以传入subscribe的参数是模板类型ObserverType
*/
    void subscribe(ObserverType* obsver)
    {
        auto tmp = std::find(obj_list.begin(), obj_list.end(), obsver);
        if (tmp == obj_list.end()) {
            obj_list.push_back(obsver);
        }
    }

    void unsubscribe(ObserverType* obsver)
    {
        obj_list.erase(std::remove(obj_list.begin(), obj_list.end(), obsver));
    }
    //执行obj_list里面对应的回调函数,比如上面的catObserver->onPublish(),
    //希望可以执行任意形式的回调函数
    template <typename FuncType>
    void publish(FuncType func)
    {
        for (auto obs: obj_list)
        {
            //调用回调函数,将obs作为第一个参数传递,否则类的方法不可调用
            func(obs);
        } 
    }

private:
    std::vector<ObserverType*> obj_list;
};

// #include "Subject.h"
#include "VistorMode.h"
#include <functional>
#include <iostream>


using std::cout;
using std::endl;
using std::bind;

class catObserver {
public:
    virtual void onMiao() = 0;
public:
    virtual ~catObserver() {} // 避免内存泄漏
};


class Jerry : public catObserver {
public:
    void onMiao() { // 3.jerry听到tom叫执行的动作,需要在tom的publish去调用
        Run();
    }  

private:
    void Run() {
        cout << "hear tom miao,jerry run" << endl;
    }
};



class Tom : public Subject<catObserver>
{
public:
    void Miao() {
        publish(std::bind(&catObserver::onMiao, std::placeholders::_1));
    }
};


int main()
{
    Tom tom;
    Jerry jerry;
    //1. jerry 看着tom
    tom.subscribe(&jerry);
    //2.tom 叫
    tom.Miao();
    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在不使用信号的情况下,我们可以使用线程和回调函数来实现观察者模式的异步通信。 具体实现步骤如下: 1. 定义一个观察者类,其包含一个回调函数指针,用于处理被观察者发出的事件。 2. 定义一个被观察者类,其包含一个观察者的指针列表,以及一个通知观察者的函数。 3. 在被观察者类,通知观察者时,使用线程来异步执行通知操作。 4. 在观察者类,将自己的回调函数指针注册到被观察者的观察者指针列表。 5. 当被观察者需要通知观察者时,遍历观察者指针列表,异步执行每个观察者的回调函数。 下面是一个简单的示例代码: ``` // 观察者类 class Observer { public: virtual void handleMessage(const QString& message) = 0; }; // 被观察者类 class Subject { public: void addObserver(Observer* observer) { m_observers.append(observer); } void removeObserver(Observer* observer) { m_observers.removeOne(observer); } void sendMessage(const QString& message) { // 使用线程异步执行通知操作 QFuture<void> future = QtConcurrent::run([=]() { for (Observer* observer : m_observers) { observer->handleMessage(message); } }); } private: QList<Observer*> m_observers; }; // 具体的观察者类 class ConcreteObserver : public Observer { public: void handleMessage(const QString& message) override { qDebug() << "Received message: " << message; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建观察者和被观察者对象 ConcreteObserver observer; Subject subject; // 注册观察者的回调函数到被观察者的观察者指针列表 subject.addObserver(&observer); // 发送消息 subject.sendMessage("Hello World!"); return a.exec(); } ``` 在上面的示例代码,当被观察者需要通知观察者时,使用线程异步执行通知操作,遍历观察者指针列表,异步执行每个观察者的回调函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值