-
Notifications
You must be signed in to change notification settings - Fork 150
Observer
事件驱动机制的主要用途是在不同模块之间实现松耦合(相互隔离)、将复杂的调用流程分离为多个独立操作片断、实现功能扩展点。
事件驱动机制的具体例子见 example\observerex。
定义事件类型主要是定义唯一的字符串以便区分不同的事件,同时为了在编译阶段识别格式错误,自动定义了内部类型。
注册响应函数是将多个相同格式的响应函数(回调函数)记录下来,同时关联到一个事件类型字符串。
触发事件就是根据事件类型字符串找到对应的响应函数,按注册先后顺序依次调用这些响应函数(同步调用方式),将事件参数传到响应函数的形参。
下面是 x3c 框架中的事件驱动机制原理图,可参考:
- 在H文件中定义事件类型:
- 包含 eventobserver.h
- 使用 X3DEFINE_EVENT_1 等宏定义每个事件类型
- 定义和实现响应函数(普通全局函数或类的静态函数)
- 响应函数的返回值类型和形参列表必须与事件类型的定义一致
- 使用 X3_REGISTER_OBSERVER 宏注册响应函数
- 在模块的入口函数CPP文件中包含 observerimpl.h 文件
- 使用辅助类(Fire事件名称)触发事件,指定事件参数
- 在模块的入口函数CPP文件中包含 observerimpl.h 文件
在一个H文件中可定义多个事件类型,例如 myevents.h:
#include <observer/fireevent.h>
// void func(int& result)
X3DEFINE_EVENT_1(EventAdd, int&, "data.cms");
// void func(int& result, int extra)
X3DEFINE_EVENT_2(EventAddExtra, int&, int, "data.cms");
// bool func(int& result)
X3DEFINE_EVENT_1Break(EventBreakDemo, int&, "data.cms");
在该文件中首先包含 fireevent.h,然后使用 X3DEFINE_EVENT_1 等宏定义每一个事件类型,使用格式如下:
X3DEFINE_EVENT_0、_1、_2 对应的响应函数的返回值类型为 void,每个响应函数都将依次调用。
X3DEFINE_EVENT_0(事件名称, 事件名称标识后缀);
X3DEFINE_EVENT_1(事件名称, 形参类型, 事件名称标识后缀);
X3DEFINE_EVENT_2(事件名称, 形参类型1, 形参类型2, 事件名称标识后缀);
X3DEFINE_EVENT_0Break、_1Break、_2Break 的格式与上相同,对应的响应函数的返回值类型为 bool,响应函数返回false时不再分发给后续的响应函数。
事件名称 将用于定义一个内部结构体和事件触发的辅助类(类名以Fire开头),在触发和响应事件时将使用该事件名称;
形参类型 为响应函数的形参类型,最多两个形参,可以使用普通类型(例如char*、int),或引用类型(例如 string&,const MyObj&);
事件名称标识后缀 用于避免不同模块中出现相同的事件名称,内部将事件名称和标识后缀组合形成一个不重复的字符串常量,例如"EventAdd.mypkg.x3"、"EventAdd.data.cms"。
使用静态函数来响应简单事件类型,函数的返回值类型和形参列表必须与事件类型的定义一致。可使用普通全局函数或类的静态函数,例如:
void InsertNodeFunc(int& result) {...}
void MyClass::InsertNode(int& result) {...}
在响应函数所在模块的 x3InitializePlugin() 函数或其他函数中注册这些响应函数到对应的事件类型上。使用 X3_REGISTER_OBSERVER 宏注册响应函数,例如:
#include "myevents.h"
void registerHandlers()
{
X3_REGISTER_OBSERVER(EventAdd, InsertNodeFunc);
X3_REGISTER_OBSERVER(EventAdd, &MyClass::InsertNode);
}
在响应函数所在模块的入口函数CPP文件(module.cpp 或 main.cpp,包含了pluginimpl.h或实现了createObject函数) 中,需要包含observerimpl.h文件,在该模块中只能在一个CPP文件中包含observerimpl.h文件: #include <observer/observerimpl.h>
。
触发事件时需要指定事件的上下文参数,这些参数将转换为响应函数的形参。使用辅助类(类名以Fire开头,然后是事件名称)触发事件。
然后就可以使用 FireEventAdd(0).fireEvent()
、FireEventAddExtra(10, 20).fireEvent()
来触发消息。
下面是事件触发的示例:
bool test()
{
int addvalue = 0;
if (FireEventAdd(addvalue).fireEvent().param != 310) // 10 + 100 + 200
return false;
if (FireEventBreakDemo(1234).fireEvent().param != 11) // call OnBreakDemo1 once.
return false;
return true;
}