【问题标题】:DDD CQRS ES - domain object is now exposed to the presentation layer?DDD CQRS ES - 域对象现在暴露给表示层?
【发布时间】:2013-08-22 21:42:09
【问题描述】:

我的问题很简单——在普通的 DDD 域中,对象不应该暴露给表示层(除了有些人更喜欢它——我相信裸对象是怎么称呼的)。但是 CQRS + ES 呢?写入被委托给封装的算法(Events + Sagas),它使用我相信的存储库,然后更新调用它的对象(使用更改的字段/字段)。所以有一些事务逻辑和任何与一致性强制相关的东西......我说的对吗?

【问题讨论】:

    标签: dns domain-driven-design cqrs


    【解决方案1】:

    命令和查询位于您的域之上。您的表示层与该层对话。

    来自我的earlier blogpost

    命令通过明确的方式帮助您支持无处不在的语言 在系统边界捕获用户意图 - 思考使用 案例。您可以将它们视为正在发送到您的 领域。在这方面,它们还可以作为您域的一层 - 内外脱钩,让你逐渐 在内部引入概念,而不破坏外部。这 命令执行器为您提供了一个很好的管道,您可以利用它 集中安全性、性能指标、日志记录、会话 管理等等。

    命令代表一个用例。

    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)
        }
    }
    

    请注意,事件通常以最终一致的方式处理。这样做的好处是系统的性能和稳定性。

    【讨论】:

    • 它看起来很棒,并且以极其自然的方式解决了很多问题......但是为什么发明和使用它的人声称它应该只用于我们应用程序中的核心有界上下文?例如汇款系统。
    • 当你在做 CRUD 时,这不会带来任何附加值。
    猜你喜欢
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 2018-06-19
    • 2020-08-17
    • 2016-11-27
    • 2010-12-01
    相关资源
    最近更新 更多