事件驱动系统用于减少具有各种类型的多对多对象交互的大型系统中的依赖性。因此,它们的目标是在任意对象之间传递任意信息。这通常通过注册事件 handlers
来完成用event_manager
, 在 handler
中使用类型删除,即:
void handle_some_event(event *e) {/*Downcast e to an assumed appropriate type and work with it*/}
但是,假设我们想要实现这样一个没有类型删除的系统。似乎某些语言特性,尤其是泛型,应该使之成为可能。 handler
在event_manager
注册可以模板化,即(松散地):
template<typename event_type>
void event_manager::register_handler(std::function<void(event_type)> handler) {
// Implementation
}
奋斗的是,应该怎样//Implementation
这个功能是?收到处理程序后,需要将其存储到与event_type
相关的容器中.但是为了避免类型删除,必须有一个容器 per event_type
.
一个可能的选择是在模板类中使用静态容器,即:
template<typename event_type>
class handler_container {
public:
inline static std::vector<std::function<void(event_type)>> handlers;
};
event_manager
可以在相应的 handler_container<event_type>::handlers
中存储和执行处理程序容器。但是,这有一个明显的缺点,即实际上只能有一个 event_manager
。 ,鉴于容器是静态的,因此在所有 event_managers
之间共享.也许这对大多数应用程序来说已经足够了,但它仍然是一个丑陋的解决方案。
是否有任何设计模式可以更清晰地解决此问题?
最佳答案
不是设计模式,但理论上它看起来像是 std::variant
的潜在用例.您可以将事件类型定义为所有可能事件选项的 std::variant
的别名,并且您的处理程序将是 C++20 的 template lambdas。使用 constexpr if
检查他们想要的类型.最后,生成事件的代码使用适当的事件类型初始化 std::variant
,并使用 std::visit
调用所有处理程序。 .
std::variant
的使用似乎是一个潜在的可伸缩性问题,但如果处理程序编写得当,它们在添加更多变体时不应中断。
我不知道有任何使用这种“技术”的主要项目,所以我不会立即在生产代码中使用它。此外,它需要 C++20 才能在没有(太多)样板的情况下编写它,因此它可能不适用于大多数用例。但它看起来可行并且不需要类型删除。
关于c++ - 在没有类型删除的情况下用 C++ 构建事件驱动系统的设计模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70415237/