CQRS命令和事件作为泛型类?

Hol*_*ann 3 cqrs

在我看到的大多数示例中,命令和事件都表示为类.这意味着您必须使用name属性编写CorrectNameCommand类,并使用name属性编写NameCorrectedEvent类.鉴于在大多数情况下命令和事件都被序列化和反序列化并发送给其他方(编译时类型安全),这个显式类相对于更通用的类有什么优势?

例:

具有Name(表示命令类型)的Command类,应该处理命令的ag的键以及任何其他参数的对象数组或名称/值对.

一个Event类基本相同(也许我们可以将共享部分放在CommandEventBase类中).

命令(和事件)处理程序现在要检查命令(事件)的名称而不是它的类类型,并且必须依赖列表中参数的正确性(就像解串器必须依赖序列化格式是正确的一样) ).

这是一个好方法吗?如果是,为什么不在样本和教程中使用它?如果没有,有什么问题?

Mar*_*ann 6

复制

这是一个公平的观点,当序列化命令和事件时,编译时安全性会丢失,但在静态类型语言中,我仍然更喜欢强类型的命令和事件类型.

这样做的原因是它为您提供了一个代码库,负责解释消息元素.序列化往往是(类型)安全的; 反序列化是您可能遇到问题的地方.

不过,我更愿意在一个地方处理任何此类问题,而不是分散在整个代码库中.

这与事件特别相关,因为您可能有多个事件处理程序处理相同类型的事件.如果您将事件视为弱类型字典,则需要在每个事件处理程序中复制Tolerant Reader的实现.

另一方面,如果将事件和命令视为强类型,则反序列化器可以是您必须维护的单个容错读取器.

类型

所有这些说,我可以理解为什么你用C#或Java等语言发现为每条消息定义不可变的DTO似乎需要很多开销:

public sealed class CorrectNameCommand
{
    private readonly string userId;
    private readonly string newName;

    public CorrectNameCommand(string userId, string newName)
    {
        this.userId = userId;
        this.newName = newName;
    }

    public string UserId
    {
        get { return this.userId; }
    }

    public string NewName
    {
        get { return this.newName; }
    }

    public override bool Equals(object obj)
    {
        var other = obj as UserName;
        if (other == null)
            return base.Equals(obj);

        return object.Equals(this.userId, other.userId)
            && object.Equals(this.newName, other.newName);
    }

    public override int GetHashCode()
    {
        return this.userId.GetHashCode() ^ this.newName.GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

事实上,这似乎是很多工作.

这就是我现在更喜欢其他语言来实施CQRS的原因.在.NET上,F#非常适合,因为以上所有代码都归结为这个单行代码:

type CorrectNameCommand = { UserId : string; NewName : string }
Run Code Online (Sandbox Code Playgroud)

这就是我要做的,而不是传递弱类型的词典.上次我听到Greg Young谈到CQRS(NDC Oslo 2015),他似乎也"转换"为F#.

  • 您是否考虑过仅定义F#中的类型,并将它们打包到库中?从C#开始,这些记录将看起来像不可变类(基本上与我的C#示例中的`CorrectNameCommand`类无法区分;这就是它们编译的内容). (2认同)