前提: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;
}