复制
这是一个公平的一点是,当命令和事件序列化,编译时安全性丢失,但在一个静态类型语言,我还是更喜欢强类型的命令和事件类型。
原因是它给了你一个负责解释消息元素的代码库。序列化往往是相当(类型)安全的;反序列化是您可能遇到问题的地方。
不过,我宁愿在一个地方处理任何这样的问题,而不是分散在整个代码库中。
这对事件特别重要,因为您可能有多个事件处理程序处理相同类型的事件。如果您将事件视为弱类型的字典,则需要在每个事件处理程序中执行 重复。另一方面,如果您将事件和命令视为强类型,则您的反序列化器可以是您必须维护的单个容错读取器。
类型
这一切说,我能理解你为什么,如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();
}
}
那的确,好像很多工作。
这就是我最近更喜欢其他语言来实现CQRS的原因。上 。NET,F#是一个完美的结合,因为所有上面的代码归结为一个班轮:
type CorrectNameCommand = { UserId : string; NewName : string }
这就是我想要做的,而不是通过弱类型周围字典。上次我听说格雷格扬谈论CQRS(NDC奥斯陆2015)时,他似乎也“转换”为F#。
我会说这是关于可读性和明确。您会看到Command需要什么,并且您可以看到Event提供的内容。重要价值对在这里不是很有帮助。同样使用命名约定,很容易使用Ioc-Container来创建正确的Command和EventHandler。 – Jehof
所以这是一个折衷?我还编写了一个通用命令处理程序,该处理程序可以自动调度到ag上具有匹配名称和匹配参数的方法。这甚至消除了为每个命令编写命令处理程序的工作(但不禁止它)。 –
这不是说你有一个有很多方法处理你的命令的大类吗?而不是一个类处理每个命令? –