熟悉.NET的人都知道, .NET使用委托可以快速实现观察者模式,免去写很多繁杂重复的代码。遗憾的是,C++并没有提供这样的模型,为了达到相似的目的,需要继承一个类并重写virtual方法,这种做法需要写很多代码,效率比较低下。然而,在强大的C++面前,没有什么是不可能的,已经有很多人针对这个问题进行过研究,并且实现了各种委托模型,其中最著名的就是FastDelegate。为了让使用FastDelegate更象.NET,我新添加几个模板,主要如下:
首先添加一个两个类用于模拟事件发生源及事件参数类:
// 定义事件发送源(类似于.net的sender)
class IEventSource
3: {
public:
virtual ~IEventSource (){}
6: };
7:
namespace fastdelegate;
9:
// 定义标准的事件参数
class CEventArgs
12: {
public:
void)
15: {
FALSE;
17: }
18:
19: BOOL bHandled;
20: };
然后是定义一个事件句柄管理类:
// 定义事件句柄,用于管理事件中加入的委托
class TBase>
class CEventHandlerBase
4: {
public:
virtual ~CEventHandlerBase ()
7: {
int i = _delegates.GetSize () - 1; i >= 0; i --)
9: {
delete (TBase*) _delegates[i];
11: }
12: _delegates.Empty ();
13: }
14:
return _delegates.GetSize (); }
16:
// 添加委托
operator += (TBase& eventDelegate)
19: {
new TBase (eventDelegate));
21: }
22:
// 删除委托
operator -= (TBase& eventDelegate)
25: {
int i = _delegates.GetSize () - 1; i >= 0; i --)
27: {
if (*((TBase*) _delegates[i]) == eventDelegate)
29: {
delete (TBase*) _delegates[i];
31: _delegates.Remove (i);
32: }
33: }
34: }
35:
public:
37: CStdPtrArray _delegates;
38: };
最后定义一个宏用于快速创建事件句柄:
// 定义生成事件句柄的类 handleClass 为句柄类名称,eventClass 为参数类名称
#define DEFINE_EVENT_HANDLER(handleClass, eventClass) \
typedef FastDelegate2<IEventSource *, eventClass *> eventClass##Delegate;\
public CEventHandlerBase<eventClass##Delegate>\
5: {\
public:\
void Fire (IEventSource* sender, eventClass* e)\
8: {\
int i = _delegates.GetSize () - 1; i >= 0; i --)\
10: {\
11: (*(eventClass##Delegate*) _delegates[i]) (sender, e);\
12: }\
13: }\
14: }
15:
16: DEFINE_EVENT_HANDLER (CStdEventHandler, CEventArgs);
使用如有两种情况,一是只用CEventArgs参数类型就可以满足要求,二是需扩展自己的参数类型。如果需要扩展参数,代码如下:
public CEventArgs
2: {
public:
int delta1);
5:
int delta;
7: };
8:
// void handler (IEventSource* sender, CMouseEventArgs* e);
10: DEFINE_EVENT_HANDLER (CMouseEventDelegate, CMouseEventArgs);
应用代码示例如下:
public IEventSource
2: {
private:
void);
public:
void);
7:
void);
9:
// 定义鼠标点击事件
11: CMouseEventDelegate MouseClick;
12:
13: ……
protected:
int nCode, WPARAM wParam, LPARAM lParam)
16: {
17: CGlobalWindowMsgHook* This = instance();
18: PMSLLHOOKSTRUCT hookStruct = (PMSLLHOOKSTRUCT)lParam;
19:
int msg = wParam;
int x = hookStruct->pt.x;
int y = hookStruct->pt.y;
short)((hookStruct->mouseData >> 16) & 0xffff);
24:
if (msg == WM_LBUTTONUP)
26: {
// 触发鼠标点击事件
28: This->MouseDown.Fire (This, &CMouseEventArgs (Left, 0, x, y, delta));
29: }
30: ……
31: }
32: ……
33: };
34:
// 测试类
class CTest
37: {
public:
39: CTest ()
40: {
this, &CTest::MouseDownHandler);
42: }
43: ~CTest ()
44: {
this, &CTest::MouseDownHandler);
46: }
47:
void MouseDownHandler (IEventSource* sender, CMouseEventArgs* e)
49: {
));
51: }
52: }