我正在使用 CQRS 和 MediatR 库,试图学习一些最佳实践。我发现很难理解如何将所有业务逻辑拆分为命令和查询。
这是一个例子:
我有一个 Address
实体,我已经创建了两个命令和一个查询:InsertAddressCommand
、UpdateAddressCommand
和 GetAddressByUserIdQuery
。
控制器中有端点负责执行插入、更新或负责按用户 ID 返回地址。
还有一个名为 UpdateOrInsertAddress
的端点,它重用了 2 个命令和 1 个查询:首先通过用户 id 获取地址并根据结果执行插入或更新。
到目前为止一切顺利。
现在,还有另一个端点 SubmitPurchaseOrder
正在接收一个更大的对象。与购买相关的所有信息都会立即收到。送货地址和账单地址是发布对象的一部分。
然后我想重用 UpdateOrInsertAddress
中的逻辑,因为所有逻辑都已经存在(而且我被教导重用代码);但由于 UpdateOrInsertAddress
是一个端点,我无法从另一个端点 (SubmitPurchaseOrder
) 执行它。
那么问题来了:在这种情况下,最佳实践是什么?
我的一些想法:
UpdateOrInsertAddress
端点中的逻辑移动到控制器中的另一个方法,并从 UpdateOrInsertAddress
和 SubmitPurchaseOrder
端点重用它。在这种情况下,我会将逻辑放入控制器中,但我不知道这是否正确。UpdateOrInsertAddress
命令,供两个端点使用。在这种情况下,该命令中将重复通过用户 id 检索地址、更新或插入的“逻辑”。你遇到过这样的场景吗?最佳做法是什么?
答案 0 :(得分:2)
嗯...首先你必须问自己是否会发生UpdateOrInsertAddress
逻辑改变的情况,但你仍然想在SubmitPurchaseOrder
中使用旧逻辑,换句话说:是UpdateOrInsertAddress
逻辑与 SubmitPurchaseOrder
紧密耦合,它应该总是在两个地方一起改变吗?
如果 UpdateOrInsertAddress
逻辑 IS 与 SubmitPurchaseOrder
紧密耦合,那么不要使事情过于复杂并使用简单的重构技术,例如“提取方法”要重用代码(您的第一个想法对此很有效),只需将该方法设为私有以供内部使用。这并不意味着您将逻辑放入控制器中,您只是在重构,如果您担心,您甚至可以将这两个端点隔离在它们自己的控制器中,这样其他端点就不会看到共享代码。
如果 UpdateOrInsertAddress
逻辑 IS NOT 与 SubmitPurchaseOrder
结合,那么复制代码(您的第三个想法)是一个非常明显的选择,因为即使视觉代码看起来相同,两个副本都有其存在的理由。复制条件时你必须小心,它们可能代表一些业务规则(你应该评估它),应该被提取到域宽策略(例如:只有用户年龄 >= 18 可以注册等)并在共享代码之间重用,以保护您免受业务规则更改的影响。
与 CQRS 相比,您的问题更多地与常见的编程实践有关。