领域对象不应该有任何依赖性,因此也不需要进行依赖注入。然而,当在领域对象内部分派领域事件时,我可能希望使用集中式的 EventDispatcher
。那么我如何获取一个呢?
我不想将事件列表返回给调用者,因为我希望它们保持不透明并保证它们的分派。这些事件只应由其他需要执行最终一致性约束的领域对象和服务来消耗。
领域对象不应该有任何依赖性,因此也不需要进行依赖注入。然而,当在领域对象内部分派领域事件时,我可能希望使用集中式的 EventDispatcher
。那么我如何获取一个呢?
我不想将事件列表返回给调用者,因为我希望它们保持不透明并保证它们的分派。这些事件只应由其他需要执行最终一致性约束的领域对象和服务来消耗。
基本上,您需要为您的领域事件注册一个或多个处理程序,然后像这样引发事件:
public class Customer
{
public void DoSomething()
{
DomainEvents.Raise(new CustomerBecamePreferred() { Customer = this });
}
}
所有已注册的处理程序将被执行:
public void DoSomethingShouldMakeCustomerPreferred()
{
var c = new Customer();
Customer preferred = null;
DomainEvents.Register<CustomerBecamePreferred>(p => preferred = p.Customer);
c.DoSomething();
Assert(preferred == c && c.IsPreferred);
}
这基本上是实现了Hollywood Principle (别打电话给我们,我们会打给你),因为你不直接调用事件处理程序,而是在事件被触发时执行事件处理程序。
Dispatcher
,那么这似乎非常繁琐。我更喜欢一个静态实例或者像在ES中那样简单地记录AR上的事件。 - plalxclass MyAggregate
{
private List<IEvent> events = new List<IEvent>();
// ... Constructor and event sourcing?
public IEnumerable<IEvent> Events => events;
public string Name { get; private set; }
public void ChangeName(string name)
{
if (Name != name)
{
events.Add(new NameChanged(name);
}
}
}
然后你可能会有一个类似这样的处理程序:
public class MyHandler
{
private Repository repository;
// ... Constructor and dependency injection
public void Handle(object id, ChangeName cmd)
{
var agg = repository.Load(id);
agg.ChangeName(cmd.Name);
repository.Save(agg);
}
}
一个看起来像这样的代码仓库:
class Repository
{
private EventDispatcher dispatcher;
// ... Constructor and dependency injection
public void Save(MyAggregate agg)
{
foreach (var e in agg.Events)
{
dispatcher.Dispatch(e);
}
}
}
DomainEvents
是一种环境上下文的形式。这是一种反模式,因此Udi Dahan早就放弃了使用这个静态类来发布事件。你应该更倾向于@VoiceOfUnreason的答案。 - Steven