观察者模式
这种模式比较常见,发布和订阅的机制。
普通触发
示例:
/*观察者模式*/
#include <iostream>
#include <set>
using namespace std;
//观察者接口,包括事件响应函数
class Observer
{
public:
virtual void update(int n) = 0;
};
//目标类,负责触发事件
class Subject
{
public:
Subject() {};
//添加事件监听
void addObserver(Observer *observer)
{
observerSet.insert(observer);
}
//删除事件监听
void removeObserver(Observer *observer)
{
observerSet.erase(observer);
}
//触发事件
void notify(int n)
{
set<Observer *>::iterator iter;
for (iter = observerSet.begin(); iter != observerSet.end(); ++iter)
{
(*iter)->update(n);
// iter. ->update();
}
}
private:
set<Observer *> observerSet;
};
class Observer1 :public Observer
{
public:
void update(int n)
{
cout << "观察者1事件响应函数,接受参数:" << n << endl;
}
};
class Observer2 :public Observer
{
public:
void update(int n)
{
cout << "观察者2事件响应函数,接受参数:" << n << endl;
}
};
int main()
{
Subject subject;
Observer * observer1 = new Observer1();
Observer * observer2 = new Observer2();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify(4);
subject.notify(1);
cout << endl;
subject.removeObserver(observer1);
subject.notify(5);
getchar();
return 0;
}
输出:
观察者1事件响应函数,接受参数:4
观察者2事件响应函数,接受参数:4
观察者1事件响应函数,接受参数:1
观察者2事件响应函数,接受参数:1
观察者2事件响应函数,接受参数:5
回调函数触发
代码:
#include <iostream>
#include <set>
#include <functional>
#include <list>
#include <algorithm>
#include <string>
using namespace std;
/* 实现事件的信号类 */
template <typename... TFuncArgs>
class Signal
{
public:
using Callback = std::function<void(TFuncArgs...)>;
/*
连接类, 一旦结束,Disconnect()将被自动调用。
*/
class SignalConnection
{
private:
friend class Signal;
/* 只允许类Signal创建连接 */
SignalConnection(Signal& signal, int id) noexcept:id(id), signal(signal) {}
public:
/* C++11 成员函数声明新特性: = delete,从逻辑语义上禁止了对于SignalConnection类拷贝构造函数和赋值运算符*/
SignalConnection(const SignalConnection& copy) = delete;
/* 如果没有复制构造函数,则不能返回SignalConnection,除非提供一个move构造函数。 */
SignalConnection(SignalConnection&& toMove) noexcept : id(toMove.id), signal(toMove.signal), disconnected(toMove.disconnected) {}
~SignalConnection()
{
Disconnect();
}
int id;
Signal& signal;
bool disconnected = false;
void Disconnect()
{
if (disconnected)
return;
disconnected = true;
signal.Disconnect(*this);
}
};
/* 返回连接对象,连接对象一旦超出作用域将自动断开连接 */
SignalConnection Connect(Callback callback)
{
callbacks.push_back(std::pair<int, Callback>(idRoller++, callback));
return SignalConnection(*this, idRoller - 1);
}
void Invoke(TFuncArgs... args)
{
for (auto& con : callbacks) {
(con.second)(args...);
}
}
void operator()(TFuncArgs... args)
{
Invoke(args...);
}
private:
/* ID Counter.
使用id查找连接对应的回调函数,因为std::function的操作符==并不像想象的那样工作。*/
int idRoller = 0;
std::list< std::pair<int, Callback> > callbacks;
void Disconnect(SignalConnection& t)
{
callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(), [&](auto& pCallback) {
return pCallback.first == t.id;
}), callbacks.end());
}
};
void TestFunc1(int t)
{
cout << "Func1: t = " << t << endl;
}
void TestFunc2(int t, string someArg)
{
cout << "Func2: t = " << t << " someArg = " << someArg << endl;
}
int main()
{
using TestDelegate = Signal<int>;
TestDelegate testEvent;
TestDelegate::SignalConnection testCon1 = testEvent.Connect(&TestFunc1);
TestDelegate::SignalConnection testCon2 = testEvent.Connect(std::bind(TestFunc2, std::placeholders::_1, "arg")); //用bind去绑定参数
auto testCon3 = testEvent.Connect(&TestFunc1); //用auto简化声明
testEvent(1);
getchar();
return 0;
}
输出:
Func1: t = 1
Func2: t = 1 someArg = arg
Func1: t = 1
参考:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2021-09-18 C# 集合之 ArrayList
2021-09-18 英语|你能明白我的意思吗