当命令需要结果数据时,如何应用命令查询分离(CQS)?
在维基百科的命令查询分离定义中,有人说
更正式地说,方法应该只返回一个值
如果它们是引用透明的
因此没有副作用。
如果我发出命令,我该如何确定或报告该命令是否成功,因为通过此定义,该函数无法返回数据?
例如:
string result = _storeService.PurchaseItem(buyer, item);
此调用中包含命令和查询,但查询部分是命令的结果。我想我可以使用命令模式重构这个,如下所示:
PurchaseOrder order = CreateNewOrder(buyer, item);
_storeService.PerformPurchase(order);
string result = order.Result;
但这似乎增加了代码的大小和复杂性,这对于重构来说并不是一个非常积极的方向。
当您需要操作结果时,有人能给我一个更好的方法来实现命令查询分离吗?
我在这里错过了什么吗?
谢谢!
笔记:
Martin Fowler对此有关cqs CommandQuerySeparation的限制:
Meyer喜欢使用命令查询
绝对分离,但有
例外。弹出堆栈是一件好事
修改的修饰符示例
州。梅耶正确地说你
可以避免使用这种方法,但它
是一个有用的成语。所以我更喜欢
我尽可能遵循这个原则,但是
我准备打破它以获得我的
流行。
从他的观点来看,重构命令/查询分离几乎总是值得的,除了一些小的简单例外。
没有找到相关结果
已邀请:
9 个回复
提孺局缎
是处理购买的合适命令。这会产生一个
。这是一种更好的方式,而不是在
中返回收据。为了使事情变得非常简单,您可以从命令返回收据并在此处违反CQRS。如果您想要更清晰的分离,该命令将引发您可以订阅的
事件。 如果你考虑你的域名,这实际上可能是一个更好的模型。当您在收银台结账时,您可以按照此流程进行操作。在您的收据生成之前,可能需要进行信用卡检查。这可能需要更长时间。在同步场景中,您将在收银台等待,无法执行任何其他操作。
捻盒愧杯
诞胃
锹缄
抢垢洛韧
现在您可以使用“Command”方法,如下所示:
灰色区域的问题是它很容易被滥用。将新订单ID等返回信息放入Monad将允许消费者说“忘记等待活动,我们就在这里获得了ID !!!”此外,并非所有命令都需要Monad。你真的应该检查你的应用程序的结构,以确保你真正达到了边缘情况。 使用Monad,现在您的命令消耗可能如下所示:
在距离很远的代码库中。 。 。
在远在遥远的GUI中。 。 。
现在你拥有了你想要的所有功能和适当性,只有Monad的一些灰色区域,但是你确定你不会在Monad中意外暴露出一个糟糕的模式,所以你限制你可以用它来做什么。
扑北爱
您还可以为操作失败的情况设置一个块
这降低了客户端代码的圈复杂度
希望这可以帮助那些迷失的灵魂......
厦惫
将始终位于事件处理程序中,而不是之后直接在代码中。 看看这篇很棒的文章,它展示了CQS,DDD和EDA的组合。
辟官陡板休
命令处理程序实现。然后,当正常命令运行时,它将结果设置在命令结果上,然后调用者通过ICommandResult接口提取结果。使用IoC,您可以使其返回与命令处理程序相同的实例,以便您可以将结果拉回来。虽然,这可能会打破SRP。 另一种选择是使用某种共享存储,它允许您以Query随后可以检索的方式映射命令结果。例如,假设您的命令有一堆信息,然后有一个OperationId Guid或类似的东西。当命令完成并获得结果时,它将答案推送到具有该OperationId Guid作为键的数据库或另一个类中的某种共享/静态字典。当调用者返回控制权时,它会根据给定的Guid调用Query以基于结果撤回。 最简单的答案是将结果推送到命令本身,但这可能会让某些人感到困惑。我看到的另一个选项是事件,你可以在技术上做,但如果你在一个网络环境中,这使得处理起来要困难得多。 编辑 在使用了这个之后,我最终创建了一个“CommandQuery”。显然,它是命令和查询之间的混合体。 :)如果您需要此功能,则可以使用它。但是,需要有充分的理由这样做。它不会重复,也不能缓存,因此与其他两个相比存在差异。
绊伦欧
你的例子的一个缺点是,你的回归并不明显 方法。
目前尚不清楚“结果”究竟是什么。 使用CQS(命令查询分隔)可以让事情变得更加明显 类似于以下内容:
是的,这是更多的代码,但更清楚的是发生了什么。