我目前正在使用这种模式来处理来自某些事件接收器(例如企业服务总线、队列、EventStore)的事件。这个想法是在一个列表中实例化几个 IEventWorker(参见下面的具体示例)并传递事件,例如,通过在遍历列表时调用每个实例的 HandleEvent 方法。这是 IEventWorkers 具体的基本代码:
public class EventWorker : IEventWorker
{
private Dictionary<Type, Action<object>> CreateEventHandlerMapping()
{
return new Dictionary<Type, Action<object>>
{
{typeof (Event1), o => Handle(o as Event1)},
{typeof (Event2), o => Handle(o as Event2)},
};
}
private void Handle(Event1 eventToHandle)
{
}
private void Handle(Event2 eventToHandle)
{
}
public void HandleEvent(IEvent evt)
{
var eventType = evt.GetType();
if (_eventHandlerMapping.ContainsKey(eventType))
{
_eventHandlerMapping[eventType](evt);
}
}
}
也许有更好的方法来做到这一点?
附言:
This非常接近我想要实现的目标。我不完全理解 ObserverRegistry 如何分发来自事件队列等的所有事件。
最佳答案
您的问题本质上相当广泛;也许有点太多了。我鼓励您完善它。
但是,您要求潜在的改进,我至少可以想到一件足够具体的事情:
- 为了类型安全,您可以使用双重分派(dispatch)而不是类型转换。
参见 the visitor pattern了解更多信息。在您的情况下,您将在 IEvent
上创建类似 Accept
的方法,并在 HandleEvent
中调用它:
public void HandleEvent(IEvent evt)
{
evt.Accept(this);
}
事件类型的接受方法如下所示:
public void Accept(IEventWorker worker)
{
worker.Handle(this);
}
(虽然这仍然是一个虚拟调用,但请注意现在静态选择了处理程序方法重载。这与您现有的运行时字典查找形成对比。)
IEventWorker
接口(interface)会为每个事件类型指定一个方法,这相当于“注册”它们,尽管这次是以类型安全的方式进行的。请注意,这会改变他们对您的实现的访问级别,这很好。
然后您可以完全删除映射字典;您现在正在使用该类的虚拟表来达到相同的效果。
我不会跳到也声称性能改进(如果它在您的场景中甚至很重要),但如果它很重要,您可能想要测试并查看(您至少应该期望更好的性能)。
关于c# - 通过多个消费者和事件处理程序使用存储的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35196573/