使用 C++ 实现模仿 C# 风格的多播事件
使用 C++ 实现模仿 C# 风格的多播事件
引言
虽然我们有很多方法来实现观察者模式,但继承的监听器在大多数 C++ 面向对象编程中被使用。一些熟悉 C#(或 Java 等)的程序员可能熟悉非继承的委托解决方案,这是在这些编程语言中最有效的方法。 在这个技巧中,我将向你展示一种用 C++ 模仿 C# 风格多播事件系统的方法。我的实现需要 fastdelegate 库。
实现
#ifndef __EVENT_H__
#define __EVENT_H__
#include <set>
#include "FastDelegate.h"
#include "FastDelegateBind.h"
namespace kks {
/**
* @brief Base class of event
*/
template<typename HandlerT>
class _Event : public std::set<fastdelegate::FastDelegate<HandlerT> > {
public:
typedef std::set<fastdelegate::FastDelegate<HandlerT> > BaseType;
typedef fastdelegate::FastDelegate<HandlerT> Handler;
public:
/**
* @brief Register an event handler
*
* @param[in] handler - Event handler delegate
* @return - True if registeration succeed
*/
bool operator += (const Handler &handler) {
if(BaseType::find(handler) != BaseType::end())
return false;
BaseType::insert(handler);
return true;
}
/**
* @brief Unregister an event handler
*
* @param[in] handler - Event handler delegate
* @return - True if unregisteration succeed
*/
bool operator -= (const Handler &handler) {
if(BaseType::find(handler) == BaseType::end())
return false;
BaseType::erase(handler);
return true;
}
};
/**
* @brief Event class
*/
template<typename Signature>
class Event;
/**
* @brief Event class without arguments
* @note This is a final class which you cannot derive from it
*/
template<>
class Event<void(void)> : public _Event<void(void)> {
public:
typedef _Event<void(void)> BaseType;
public:
Event() {
}
Event(const Event::Handler &handler) {
this->operator += (handler);
}
/**
* @brief Raise an event
*/
void operator() (void) const {
for(const_iterator it = begin(); it != end(); ++it) {
Handler d = *it;
d();
}
}
};
/**
* @brief Event class with 1 argument
* @note This is a final class which you cannot derive from it
*/
template<typename Arg1T>
class Event<void(Arg1T)> : public _Event<void(Arg1T)> {
public:
typedef _Event<void(Arg1T)> BaseType;
public:
Event() {
}
Event(const typename Event::Handler &handler) {
this->operator += (handler);
}
/**
* @brief Raise an event
*
* @param[in] arg1 - 1st argument
*/
void operator() (Arg1T &arg1) {
for(typename BaseType::iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
typename BaseType::Handler d = *it;
d(arg1);
}
}
/**
* @brief Raise an event
*
* @param[in] arg1 - 1st argument
*/
void operator() (Arg1T arg1) const {
for(typename BaseType::const_iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
typename BaseType::Handler d = *it;
d(arg1);
}
}
};
/**
* @brief Event class with 2 arguments
* @note This is a final class which you cannot derive from it
*/
template<typename Arg1T, typename Arg2T>
class Event<void(Arg1T, Arg2T)> : public _Event<void(Arg1T, Arg2T)> {
public:
typedef _Event<void(Arg1T, Arg2T)> BaseType;
public:
Event() {
}
Event(const typename Event::Handler &handler) {
this->operator += (handler);
}
/**
* @brief Raise an event
*
* @param[in] arg1 - 1st argument
* @param[in] arg2 - 2nd argument
*/
void operator() (Arg1T &arg1, Arg2T &arg2) {
for(typename BaseType::iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
typename BaseType::Handler d = *it;
d(arg1, arg2);
}
}
/**
* @brief Raise an event
*
* @param[in] arg1 - 1st argument
* @param[in] arg2 - 2nd argument
*/
void operator() (Arg1T arg1, Arg2T arg2) const {
for(typename BaseType::const_iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
typename BaseType::Handler d = *it;
d(arg1, arg2);
}
}
};
/**
* @brief Event class with 3 arguments
* @note This is a final class which you cannot derive from it
*/
template<typename Arg1T, typename Arg2T, typename Arg3T>
class Event<void(Arg1T, Arg2T, Arg3T)> : public _Event<void(Arg1T, Arg2T, Arg3T)> {
public:
typedef _Event<void(Arg1T, Arg2T, Arg3T)> BaseType;
public:
Event() {
}
Event(const typename Event::Handler &handler) {
this->operator += (handler);
}
/**
* @brief Raise an event
*
* @param[in] arg1 - 1st argument
* @param[in] arg2 - 2nd argument
* @param[in] arg3 - 3rd argument
*/
void operator() (Arg1T &arg1, Arg2T &arg2, Arg3T &arg3) {
for(typename BaseType::iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
typename BaseType::Handler d = *it;
d(arg1, arg2, arg3);
}
}
/**
* @brief Raise an event
*
* @param[in] arg1 - 1st argument
* @param[in] arg2 - 2nd argument
* @param[in] arg3 - 3rd argument
*/
void operator() (Arg1T arg1, Arg2T arg2, Arg3T arg3) const {
for(typename BaseType::const_iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
typename BaseType::Handler d = *it;
d(arg1, arg2, arg3);
}
}
};
// Add more if you wish.
}
#endif // __EVENT_H__
Using the Code
按照以下步骤使用此代码页面
- 你可能应该创建一个事件类型定义,因为它能简化后续的编码和维护
typedef Event<void(Arg1T, Arg2T, ...)> SomeEvent;
- 你可以使用该定义来声明一个事件
SomeEvent OnSomeEvent;
- 如果发生某些事情,使用以下方式触发一个事件
OnSomeEvent(Arg1, Arg2, ...);
- 要注册一个观察它的事件处理程序,请编写
obj->SomeEvent += SomeEvent::Handler(Class*, &Class::Method);
- 不要忘记在某人不再观察该事件时,通过以下方式取消注册处理程序
obj->SomeEvent -= SomeEvent::Handler(Class*, &Class::Method);
- 定义事件的一种常用模式是这样的
Event<void(Sender*, EventArgsStruct*)>
其中“Sender
”是事件触发者,而“EventArgsStruct
”是一个常见的结构体,它封装了详细的事件参数;这是一种源自 C# 的用法。