当命令需要结果数据时,如何应用命令查询分离(CQS)?

Mar*_*ers 62 c# command-query-separation

在维基百科的命令查询分离定义中,有人说

更正式地说,方法只有在它们是引用透明的情况下才能返回值,因此没有副作用.

如果我发出命令,我该如何确定或报告该命令是否成功,因为通过此定义,该函数无法返回数据?

例如:

string result = _storeService.PurchaseItem(buyer, item);
Run Code Online (Sandbox Code Playgroud)

此调用中包含命令和查询,但查询部分是命令的结果.我想我可以使用命令模式重构这个,如下所示:

PurchaseOrder order = CreateNewOrder(buyer, item);
_storeService.PerformPurchase(order);
string result = order.Result;
Run Code Online (Sandbox Code Playgroud)

但这似乎增加了代码的大小和复杂性,这对于重构来说并不是一个非常积极的方向.

当您需要操作结果时,有人能给我一个更好的方法来实现命令查询分离吗?

我在这里错过了什么吗?

谢谢!

注意:Martin Fowler对此有关cqs CommandQuerySeparation的限制:

Meyer绝对喜欢使用命令查询分离,但也有例外.弹出堆栈是修改状态的修饰符的一个很好的例子.梅耶正确地说你可以避免使用这种方法,但这是一个有用的习惯用法.所以我喜欢在我可以的时候遵循这个原则,但我准备打破它以获得我的流行音乐.

从他的观点来看,重构命令/查询分离几乎总是值得的,除了一些小的简单例外.

Joh*_*lph 42

这个问题已经过时了,但还没有得到令人满意的答案,所以我将在近一年前对我的评论进行详细阐述.

使用事件驱动的体系结构非常有意义,不仅可以实现清晰的命令/查询分离,还因为它打开了新的体系结构选择,并且通常适合异步编程模型(如果需要扩展体系结构,则非常有用).通常情况下,您会发现解决方案可能在于对您的域建模有所不同.

所以让我们以您的购买为例.StoreService.ProcessPurchase将是处理购买的合适命令.这会产生一个PurchaseReceipt.这是一种更好的方式,而不是返回收据Order.Result.为了使事情变得非常简单,您可以从命令返回收据并在此处违反CQRS.如果您想要更清晰的分离,该命令将引发ReceiptGenerated您可以订阅的事件.

如果你考虑你的域名,这实际上可能是一个更好的模型.当您在收银台结账时,您可以按照此流程进行操作.在您的收据生成之前,可能需要进行信用卡检查.这可能需要更长时间.在同步场景中,您将在收银台等待,无法执行任何其他操作.

  • 如果命令失败怎么办?你订阅了ReceiptGenerated和ReceiptGenerattionFailed事件,如果因为某些错误而永远不会发布ReceiptGenerattionFailed怎么办? (5认同)
  • @AlexBurtsev - 由于错误而没有生成`ReceiptGenerationFailed`事件似乎是一个巨大的错误.异常处理不会合理地阻止这种情况吗? (3认同)

Rem*_*rik 13

我在CQS和CQRS之间看到了很多混淆(正如Mark Rogers在一个答案中所注意到的那样).

CQRS是DDD中的体系结构方法,在查询的情况下,您不会从聚合根及其所有实体和值类型构建完整的对象图,而只是在列表中显示的轻量级视图对象.

CQS是应用程序任何部分代码级别的良好编程原则.不只是域名区域.该原则存在的方式比DDD(和CQRS)长.它表示不会弄乱使用只返回数据的查询来更改应用程序的任何状态的命令,并且可以在不更改任何状态的情况下随时调用.在我以后的Delphi中,lan​​quage显示了功能和程序之间的差异.编码'functionprocedures'被认为是一种不好的做法,因为我们将它们调回来也是如此.

回答问题:人们可以想办法解决执行命令和取回结果的方法.例如,通过提供具有void execute方法和readonly命令结果属性的命令对象(命令模式).

但是坚持CQS的主要原因是什么?保持代码可读性和可重用性,而无需查看实现细节.您的代码应该值得信赖,不会造成意外的副作用.因此,如果命令想要返回结果,并且funcion名称或返回对象清楚地表明它是带有命令结果的命令,我将接受CQS规则的例外.不需要让事情变得更复杂.我同意Martin Fowler(如上所述).

顺便说一下:不会严格遵循这条规则打破整个流畅的api原则吗?

  • 我欢迎CQS和CQRS之间的区别以及原始问题关注CQS. (4认同)