我正致力于实施基本的CQRS + ES应用程序。我已经看过很多例子,但我不了解命令处理程序和聚合之间的路由。
在某些例子中,工作是这样做的:
XCommandHandler:
void Handle(XCommand command) {
var aggregate = this.repository.Find<Aggregate>(command.aggId);
aggregate.InvokeSomeBusinessLogic(command.property1, command.property2);
this.repository.Save(aggregate);
}
但其他人则采用另一种方式:
XCommandHandler:
void Handle(XCommand command) {
var aggregate = this.repository.Find<Aggregate>(command.aggId);
aggregate.InvokeSomeBusinessLogic(command);
this.repository.Save(aggregate);
}
最好的方法是什么,特别是在命令中有多个属性(15个或更多)时?
答案 0 :(得分:9)
这不是一个关于CQRS + ES的问题,而是关于整体API设计的问题。正如Clean Code所解释的那样,没有参数的方法比具有一个参数的方法更好,这比具有两个参数的方法更好等。
盲目遵循该规则应始终让您选择第二个选项:
aggregate.InvokeSomeBusinessLogic(command);
然而,盲目遵守任何规则很少是一个好主意。在这种情况下,将Interface Segregation Principle视为反作用力是个好主意:
客户不应该被迫依赖他们不使用的方法。
由于getter和setter也是方法,我认为这个原则也适用于命令对象。
因此,如果您有15个或更多属性,但所讨论的方法只需要其中两个,那么传递这两个值可能会更好。
另一件事是,如果你有一个包含15个属性的命令对象,你可能想重新考虑你的设计。 CQRS + ES背后的基本假设之一是应用程序呈现task-based UIs,这可确保每个命令(以及相应的事件)都很小。
使用链接在Mark的评论中进行编辑,因为其中一个链接已被破坏:
更新汇总信息不是基于任务的;它的CRUD。也许Udi Dahan的这两篇文章会有所帮助。
答案 1 :(得分:3)
我原则上同意马克的观点。然而,我会注意到CQRS已经从领域驱动的设计世界发展而来。他们强调语言的重要性(ubiquitous language)。您可以捕获命令对象的实际名称中的意图和意义。
在实际层面上,通过添加参数的重构方法如果从多个地方调用,可能会变得非常痛苦。单个对象可以显着减轻这种情况。
我有一些您可能会发现有用的相关帖子。 Aggregate Root – How to Build One for CQRS and Event Sourcing和6 Code Smells with your CQRS Events – and How to Avoid Them。虽然最后一个是关于事件的,但许多原则都适用。
希望你觉得它们很有帮助。