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 
#include 

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 
#include 


//一个带有订阅。发布的基础类
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 
#include 


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;
}

你可能感兴趣的:(设计模式,QT,Qt,观察者模式)