事件调度员的设计

时间:2017-03-04 20:38:28

标签: c++ design-patterns

有一个大的c ++项目从外部接收数据,经过小规模处理后,新数据被发送到客户端代码(在应用程序内)。现在所有客户端代码都实现了许多接口(例如IOnConcreteDataReceived),并且指向这些接口的指针被设置为从外部接收数据的部分。

事件调度程序看起来是代码解耦的不错选择。 我想获得以下代码:

// dispatcher global access
IEventDispatcher & getEventDispatcher();
//producer:
ConcreteDataType data{values};
getEventDispatcher().fireEvent<ConcreteDataTypeEvent>(data);

//consumer:
getEventDispatcher().subscribe<ConcreteDataTypeEvent>([](const ConcreteDataType & data){ processData(data);});

在大多数情况下,数据类型不同,最简单的解决方案是将数据类型用作事件类型:

//producer:
ConcreteDataType data{values};
getEventDispatcher().fireEvent<ConcreteDataType>(data);

//consumer:
getEventDispatcher().subscribe<ConcreteDataType>([](const ConcreteDataType & data){ processData(data);});

the implementation is simple

我唯一不喜欢这种变体的是将数据类型用作事件类型。它看起来不直观

从数据类型中分离事件类型会导致更复杂的代码。事件类型和数据类型之间应该存在关联,可能在中心位置。

问题:设计的纯度(分离的事件类型和数据类型)是否值得额外努力或使用数据类型作为事件类型并不像我想象的那么糟糕? 如何实现事件类型的编译时检查 - 数据类型关联?

1 个答案:

答案 0 :(得分:1)

namespace notstd {
  template<class T> struct tag_t{constexpr tag_t(){} using type=T;};
  template<class T> constexpr tag_t<T> tag{};
  template<class Tag> using type=typename Tag::type;
}

这让我们可以将类型作为值来操作。这很有用,因为函数对值进行操作,而函数有ADL。

namespace dispatch_events {
  template<class T>
  constexpr notstd::tag_t<T> data_type_mapping( notstd::tag_t<T> ) { return {}; }

  template<class E>
  using data_type = notstd::type<decltype(data_type_mapping(notstd::tag<E>))>;
}

现在,dispatch_events::data_type<E>是事件E使用的数据类型。默认情况下,它只是E

如果要创建具有不同数据类型的事件,请创建如下事件类型:

namespace somewhere {
  struct some_data { int x = 0; };
}

namespace anywhere {
  struct event_bob {};

  constexpr notstd::tag_t<somewhere::some_data>
  data_type_mapping( notstd::tag_t<event_bob> ) { return {}; }
}

现在,dispatch_events::data_type< anywhere::event_bob >somewhere::some_data

您可以轻松获得常见案例的事件&lt; - &gt;数据对应关系,以及在多个事件中拥有相同数据而无需在任何地方使用中央注册表的能力。将事件类型映射到数据类型的任何人都必须具有视图中的事件类型;要使其工作,它们还必须具有data_type_mapping函数(因此也是数据类型)。

只需将data_type_mapping函数放在事件类型的命名空间中,一切都很好。

这也允许事件类型映射到基本类型,如int或您不拥有的类型,如std::shared_ptr<bob>

如果您想知道它是如何工作的,它可以工作,因为模板评估在模板声明上下文中查找并使用ADL(参数依赖查找)。 data_type_mapping的ADL发现非模板重载,然后优先于dispatch_events命名空间中的模板重载。 ADL检查参数和参数的模板参数,以查找命名空间以搜索可能的候选重载。