[Poco]信号和回调函数的处理
Poco::BasicEvent实现事件对象,类似于Qt中信号的概念,是一种类型安全的调用回调函数的方案,与之类似的还有boost中的signal和一个名为sgi++的软件包。与Poco::BasicEvent有关的类如下(Poco中还有一外名为Event的类,指的是操作系统中的事件对象,用于同步操作,与此处无关。以下为与事件机制有关的类定义。
先看一个例子,描述Poco中如何处理事件及回调函数
#include "Poco/Delegate.h"
#include <iostream>
using Poco::BasicEvent;
using Poco::Delegate;
class Source
{
public:
BasicEvent<int> theEvent;
void fireEvent(int n)
{
theEvent(this, n); // 触发一个事件
}
};
class Target
{
public:
void onEvent(constvoid* pSender, int& arg) // 定义一个事件处理函数
{
std::cout <<"onEvent: "<< arg << std::endl;
}
};
int main(int argc, char** argv)
{
Source source;
Target target;
source.theEvent += Poco::delegate(&target, &Target::onEvent);//注册事件处理函数
source.fireEvent(42); //这个函数中会触发一个事件
source.theEvent -= Poco::delegate(&target, &Target::onEvent); //注销
return0;
}
BasicEvent类的思路来自于C#,事件的接收者向事件源注册一个回调函数,事件发生之后,事件源调用这个回调函数. AbstractEvent模板表示基本事件,为具体事件提供接口,事件包括三种FIFOEvent, BasicEvent和PriorityEvent,可扩展更多种类的事件.
触发一个事件时调用AbstractEvent::operator()操作符,或是AbstractEvent::notify()函数
或
每个Event触发的函数也可以在另外一个新建的线程中执行,只要在触发事件时调用AbstractEvent::.notifyAsync(),如
向event注册回调函数时使用AbstractEvent的operator+=()函数。
source.fireEvent(42);
使用BasicEvent的一般方法是将事件声明为类的一个public成员变量,这一点与Qt的signal的概念非常类似。
使用BasicEvent的场合
用做需要通信的对象之间通信,是一种松耦合关系。Poco本身使用了大量的Event用于实现其他类型,如Poco::AbstractCache的实现中。Event在消息源和目的对象间传递一个参数,这个参数以引用形式传,可以扩展为更复杂的参数,比如Poco::Net::ICMPEventArgs就是为了扩展传递数据的能力而定义的类型。用Event的机制编程,重点就在于定义这个参数,由这个参数决定了Event的类型,这也是所谓的类型安全的意义。
BasicEvent实现的细节和高级的应用
有关BasicEvent的类型为
有关BasicEvent的实现中的函数调用顺序:
事件的接收者向事件源注册回调函数, 用Delegate类表示,该类的成员函数notify()将触发本事件的源和触发本事件时的参数传给事件的接收者。AbstractDelegate用于封装回调函数,实际用时用它的子类,Delegate类可以将类的成员函数和一般的C函数转化为Delegate类的对象,使用时使用名为delegate的一组帮助函数完成. AbstractPriorityDelegate封装回调函数,并带有优先级,有两个子类, FunctionPriorityDelegate封C函数或C++的静态函数, PriorityDelegate用于封装一般的C++类的成员函数.
事件发生后调用回调函数的策略用NotificationStrategy类表示,该类有提供两组接口函数,一组接口函数为notify转发BasicEvent类传入的参数,另一组包括add和remove为Delegate类提供一个容器. NotificationStrategy表示转发全部函数调用的一般类, 有两个子类, DefaultStrategy常用, FIFOStrategy表示先注册的回调函数先被调用.