我的问题很简单——在普通的 DDD 域中,对象不应该暴露给表示层(除了有些人更喜欢它——裸对象我相信它是怎么称呼的)。但是 CQRS + ES 呢?写入被委托给封装算法(Events + Sagas),它使用我相信的存储库,然后更新调用它的对象(使用更改的字段/字段)。所以有一些事务逻辑和任何与一致性强制相关的东西......我是对的吗?
问问题
381 次
1 回答
2
命令和查询位于您的域之上。您的表示层与该层对话。
来自我之前的一篇博文:
命令通过在系统边界显式捕获用户意图来帮助您支持无处不在的语言——想想用例。您可以将它们视为正在发送到您的域的消息。在这方面,它们还可以作为您领域的一个层 - 将内部与外部解耦,允许您逐步引入内部概念,而不会破坏外部。命令执行器为您提供了一个很好的管道,您可以利用它来集中安全性、性能指标、日志记录、会话管理等。
命令代表一个用例。
public class WithdrawMoneyCommand
{
public WithDrawMoneyCommand(string account, decimal amount)
{
// Guard and assign here..
}
public string Account { get; private set; }
public decimal Amount { get; private set; }
}
命令由命令处理程序执行。这是您对聚合进行操作的地方。无论是调用方法和更改状态,还是播放和记录新事件。事务边界位于命令处理程序级别。
public class WithdrawMoneyCommandHandler : IHandle<WithdrawMoneyCommand>
{
public void Handle(WithdrawMoneyCommand command)
{
// Get your account here, and do something with it..
}
}
这是写的一面。
在阅读方面,有人向您发送查询,您回复它。就如此容易。
public class AccountBalanceReadModel
{
public string AccountNumber { get; set; }
public decimal Value { get; set; }
}
读取模型可以动态组合查询一个或多个聚合。
public class AccountBalanceQuery
{
public string AccountNumber { get; set; }
}
public class AccountReads : IHandle<AccountBalanceQuery, AccountBalanceReadModel>
{
public AccountBalanceReadModel Handle(AccountBalanceQuery query)
{
// Do query or queries and assemble an AccountBalanceReadModel
}
}
或者(这就是事件发挥作用的地方)读取模型已经可以采用您想要的格式,因为它是通过处理事件(由聚合引发)创建的。
public class AccountReads : IHandle<AccountBalanceQuery, AccountBalanceReadModel>
{
public AccountBalanceReadModel Handle(AccountBalanceQuery query)
{
// Do simple query because your read model is already there in the way you like it
}
}
回顾如何使用事件创建读取模型,您将有一些东西处理您的事件并创建读取模型。
public class AcocuntBalanceReadModelDenormalizer : IHandle<AmountWithdrawn>
{
public void Handle(AmountWithdrawn @event)
{
// Update your specialized read model here (AccountBalanceReadModel)
}
}
请注意,事件通常以最终一致的方式处理。这样做的好处是系统的性能和稳定性。
于 2013-08-23T07:27:36.330 回答