CQRS:在ICommandExecutor.Execute()方法中返回结果是否合适?

Mou*_*Lin 3 oop cqrs

我对CQRS中的指挥部分的设计有一些想法.我想听听你对我的想法的看法.提前致谢!:)

在CQRS中,有Commands和CommandExecutors.有时我们希望命令执行程序在执行完成后返回一些结果.一种可能的解决方案是(C#):

public interface ICommandExecutor<TCommand>
{
    void Execute(TCommand cmd);
}

public interface ICommandExecutor<TCommand, TResult>
{
    TResult Execute(TCommand cmd);
}
Run Code Online (Sandbox Code Playgroud)

目前很好.我们使用两个命令执行器接口.现在让我们看看客户端代码:

var cmd = new MyCommand();
commandBus.Execute(cmd);  // execute no result
commandBus.Execute<MyResult>(cmd); // execute result
Run Code Online (Sandbox Code Playgroud)

是的,我们现在可以让执行者返回结果.但是在编写上面的代码时,程序员可能会感到困惑:这个命令能否执行结果?为了得到答案,程序员需要查看框架源代码,看看是否有MyCommandExecutor或MyCommandExecutor.这是不好的!很混乱!

所以,在我看来,我们应该删除 ICommandExecutor<TCommand, TResult>.也就是说,我认为命令执行程序应该总是返回void.设计ICommandExecutor<TCommand, TResult>很糟糕!

如果我们需要在命令执行后查看更改的内容.我们应该在调用commandBus.Execute(cmd)后对数据库进行新的查询.

你觉得怎么样?

Ste*_*ven 7

您不应该添加第二个界面.我不确定返回值是否适合CQRS中的命令,但我有时会使用我的命令执行此操作(但我不遵循CQRS).但是,不是使用第二个接口,而是向命令添加输出属性.

public class CreateCustomerCommand
{
    // customer properties here

    // output property
    public Guid CustomerId { get; internal set; }
}
Run Code Online (Sandbox Code Playgroud)

但请记住,具有输出属性的命令永远不能异步运行.

如果你真的想要一个带有返回值的执行器接口(这是我不会建议的),请看看这篇文章.本文是关于以SOLID方式实现查询,但它处理定义允许您返回数据的类型安全接口的问题.

顺便说一下,在前面的例子中,通过使CustomerId属性成为输入属性,可以很容易地使命令异步.你让客户提供一个新的随机Guid.这样,客户端已经具有可用的ID,并且不必等待结果可用.

  • "输出属性"是一个非常好的解决方案.谢谢!顺便说一句:我也是自由职业者;) (3认同)

Mik*_*erg 6

在CQRS中,命令方不应该返回任何东西,因为它破坏了模式的解剖结构.你对此的看法是正确的.

但是,Greg Young经常提到命令操作的Ack/Nack结果(或者无论如何都习惯).大多数消息框架都支持此类响应.期望结果的缺点是您不能完全异步.我从来没有觉得需要Ack/Nack,因为CQRS的基本原则之一就是命令应该总是成功,所以没有回报Ack/Nack.

问问自己你需要返回什么.什么操作需要返回您在发送/指挥方面尚未拥有的信息?在让命令成为查询之前,请花点时间弄清楚.