我一直致力于设计图书馆。其中一个方面将是 EventManager
.
到目前为止,设计是这样的:
Client client
client.on(string, function);
其中字符串是 std::string
函数是 std::function<void()>
client.on
定义如下:
void Client::on(const std::string& name, const std::function<void()>& function) {
_eventManager->add(string, function);
}
和_eventManager->add(string, function)
唯一的目标是创建一个名为 Event
的结构并将名称和功能存储在其中,然后将新的支柱推送到 vector 。
现在我可以做类似的事情:
_eventManager->emit("test");
然后它将循环 vector 数组并找到任何 event.name
这等于您调用 emit
时使用的名称并在该结构中运行函数。
这一切都有效,非常棒,很棒,但它并不是我所需要的,也不会起作用,因为我需要用 _eventManager->emit()
发送第二个参数。 .第二个参数将是未知的,也不是未知的,但它可以是基于您在第一个参数中输入的字符串的多种数据类型。
示例用法:
Client client();
client.on("ready", [](User user) {
user.test();
});
User user;
_eventManager->emit("ready", user); //I know this does not exists but it is nearly an example.
client.on("message_created", [](Message message) {
std::cout << message << std::endl; //Operator overload here
}
Message message("Something to print");
_eventManager->emit("message_created", message));
我考虑过使用 boost::variant
允许传递多种类型,但是您必须通过在函数中执行类似操作来检索它们。
client.on("ready", [](boost::variant<User, Message> args){
User user = boost::get<User>(args);
});
而且它应该也很简单,我不想让使用库的人被迫使用 boost::get
在所有事件中检索通过的类。
话虽这么说,有了上面所有精彩的信息,还有什么是我想做的事情的另一种选择?关于我为什么应该或不应该做我正在做的事情有什么建议吗?
这花了我很长时间才写出来,所以先谢谢你,我希望所有这些都有意义。
最佳答案
我有一个使用变量模板 (C++14) 的解决方案,但它看起来很糟糕。它的一个缺点是变量模板只能是静态的。假设您可以忍受它(尽管它已经很糟糕了)...
对于每种类型的消息(此处类型 = 传递给处理程序的参数列表),您将拥有一个单独的处理程序列表。这可以像这样实现:
template<typename F> static map<string, vector<F>> list;
此处 F
的示例是 void(int)
- 一个接收一个 int
参数的函数。另一个例子是 void(int, int)
- 一个接收两个 int
参数的函数。我在这里使用的数据结构为每个消息名称存储一个处理程序的 vector
。我也可以使用 multimap
。
“注册”事件处理程序时,只需将其添加到处理程序列表中即可:
template<typename F> static void add_handler(string s, F f)
{
list<F>[s].push_back(f);
}
查找事件处理程序时,您应该明确指定它们的类型。这是实现类型安全的关键部分 - 它只会在与调用处理程序的类型对应的数据结构中查找。
template<typename F, typename... A> static void call_handlers(string s, A... args)
{
for (F f: list<F>[s])
f(args...);
}
用法:
// Define event handlers
// Their type SHOULD be explicit (not lambda), because we will reference it further
function<void(int)> action1 = [](int k){cout << "notify user " << k << '\n';};
function<void(int)> action2 = [](int k){cout << "alert user " << k << '\n';};
function<void(int, int)> action3 = [](int a, int b){cout << "give $" << a << " to user " << b << '\n';};
// Register the handlers
add_handler("good_event", action1);
add_handler("good_event", action2);
add_handler("bad_event", action2);
add_handler("money_event", action3);
// Generate events, which will call the handlers
call_handlers<function<void(int)>>("good_event", 7);
call_handlers<function<void(int)>>("bad_event", 8);
call_handlers<function<void(int, int)>>("money_event", 100, 9);
// Wrong call, but no compilation error - the handler is just not found
call_handlers<function<void(int)>>("money_event", 99);
关于C++ 设计事件处理程序类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44372512/