在我正在制作的应用程序中,我有一个EventDispatcher
类,可以使用基类Event
类。调度程序不是模板化的,它适用于每个事件的运行时类型;这是为了允许脚本从基类Event
类继承并创建自己的事件类型。
它也喜欢这个事件调度程序来处理事件的继承。例如,我FooEvent
继承自FooBaseEvent
;每当FooEvent
发生时,对FooBaseEvent
感兴趣的回调也会得到通知,但不会反过来。
是否有任何图书馆可以让这更容易?请记住,继承检查也应该扩展到脚本中定义的事件。
(脚本语言是Python,但这并不重要。)
修改:我的EventDispatcher
具有以下界面(Python):
class EventDispatcher:
def subscribe(self, event_type, callback) -> EventDispatcher.Subscription
def post(self, event)
class Subscription:
def cancel(self)
def alive(self) -> bool
答案 0 :(得分:0)
我不知道任何图书馆会让你的生活更轻松,但这并不能证明它不存在。也就是说,Python和C ++的类型系统有一些重要的区别,因此找到一个通用的类型信息系统来桥接这两者可能有点棘手。
如果您只想跟踪继承层次结构并准备手动注册类型,则可以相对快速地自行注册。以下记录了type_registry_t中的层次结构,然后dispatcher_t查看层次结构以查看侦听器是否对事件感兴趣。注意使用一些c ++ 11功能。
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <map>
#include <vector>
typedef std::string class_id_t;
class type_registry_t {
std::multimap<class_id_t, class_id_t> parent_;
public:
void register_type(class_id_t const& id, std::vector<class_id_t> const& parent)
{
for (size_t i = 0, sz = parent.size(); i < sz; ++i)
parent_.insert(std::make_pair(id, parent[i]));
}
template <class out_t>
out_t all_parents(class_id_t const& id, out_t out) const
{
for (auto r = parent_.equal_range(id); r.first != r.second; ++r.first) {
*out++ = r.first->second;
out = all_parents(r.first->second, out);
}
return out;
}
};
class event_t {
public:
virtual class_id_t id() const = 0;
virtual std::vector<class_id_t> parent() const = 0;
};
inline void register_type(type_registry_t& r, event_t const& e)
{
r.register_type(e.id(), e.parent());
}
class listener_t {
std::vector<class_id_t> listen_for_;
protected:
listener_t(std::vector<class_id_t> const& listen_for)
: listen_for_ (listen_for)
{ }
public:
std::set<class_id_t> listen_for(type_registry_t const& reg) const
{
std::set<class_id_t> s;
for (size_t i = 0, sz = listen_for_.size(); i < sz; ++i) {
s.insert(listen_for_[i]);
reg.all_parents(listen_for_[i], std::inserter(s, s.end()));
}
return s;
}
virtual void notify(event_t const&) = 0;
};
class dispatcher_t {
type_registry_t const* reg_;
std::vector<std::shared_ptr<listener_t>> listener_;
public:
dispatcher_t(type_registry_t const& reg)
: reg_ (®)
{ }
void connect(std::shared_ptr<listener_t> const listener)
{
listener_.push_back(listener);
}
void signal(event_t& event)
{
class_id_t const id = event.id();
for (size_t i = 0, sz = listener_.size(); i < sz; ++i) {
std::set<class_id_t> const s = listener_[i]->listen_for(*reg_);
if (s.find(id) != s.end())
listener_[i]->notify(event);
}
}
};
这使您可以根据事件在层次结构中的位置来执行事件选择。如下所示(我认为你在你的例子中描述了这一点)。
struct foo_base_event_t : event_t {
class_id_t id() const { return "foo_base_event_t"; }
std::vector<class_id_t> parent() const
{
std::vector<class_id_t> r;
r.push_back("event_t");
return r;
}
};
struct foo_event_t : foo_base_event_t {
class_id_t id() const { return "foo_event_t"; }
std::vector<class_id_t> parent() const
{
std::vector<class_id_t> r;
r.push_back("foo_base_event_t");
return r;
}
};
struct foo_event_listener_t : listener_t {
static std::vector<class_id_t> relevant_ids()
{
std::vector<class_id_t> r;
r.push_back("foo_event_t");
return r;
}
foo_event_listener_t()
: listener_t (relevant_ids())
{ }
void notify(event_t const& e)
{
std::cout << "foo_event_listener_t::notify() with " << typeid(e).name() << " " << (void*)&e << "\n";
}
};
struct foo_base_event_listener_t : listener_t {
static std::vector<class_id_t> relevant_ids()
{
std::vector<class_id_t> r;
r.push_back("foo_base_event_t");
return r;
}
foo_base_event_listener_t()
: listener_t (relevant_ids())
{ }
void notify(event_t const& e)
{
std::cout << "foo_base_event_listener_t::notify()" << typeid(e).name() << " " << (void*)&e << "\n";
}
};
int main()
{
type_registry_t reg;
reg.register_type("event_t", std::vector<class_id_t>());
reg.register_type("foo_base_event_t", std::vector<class_id_t>(1, "event_t"));
reg.register_type("foo_event_t", std::vector<class_id_t>(1, "foo_base_event_t"));
dispatcher_t dispatcher (reg);
dispatcher.connect(std::shared_ptr<listener_t>(new foo_event_listener_t()));
dispatcher.connect(std::shared_ptr<listener_t>(new foo_base_event_listener_t()));
foo_base_event_t foo_base_event;
dispatcher.signal(foo_base_event);
foo_event_t foo_event;
dispatcher.signal(foo_event);
return 0;
}
您需要使用首选方法向Python公开其中一些内容,以允许注册事件类型。我没有包含错误检查和构造class_id的集合,每次调用listen_for()可能都很慢。