域对象不应该有任何依赖,因此也没有依赖注入。但是,当从域对象中调度域事件时,我可能希望使用集中的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); }
这基本上是在实施好莱坞原则 (不要打电话给我们,我们会打电话给你),因为你不直接调用事件处理程序 - 而是在引发事件时执行事件处理程序。
我可能想要使用集中式 EventDispatcher。我怎么能弄到一个?
将其作为参数传入。
它可能看起来不像EventDispatcher
,而是像一些以特定领域术语描述所需功能的领域服务。在编写应用程序时,您可以选择要使用的服务实现。
你要求两者兼得。您要么需要注入依赖项,要么需要反转控制并让另一个对象管理器来处理 Aggregate 和 EventDispatcher 之间的交互。我建议让你的聚合尽可能简单,这样它们就没有依赖关系并保持可测试性。
以下代码示例非常简单,不会是您投入生产的内容,但它说明了如何设计没有依赖关系的聚合,而无需在需要它们的上下文之外传递事件列表。
如果您的聚合中有一个事件列表:
class 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);
}
}
}