Domain driven design DDD存储库可以是有状态的吗?

Domain driven design DDD存储库可以是有状态的吗?,domain-driven-design,ddd-repositories,clean-architecture,hexagonal-architecture,Domain Driven Design,Ddd Repositories,Clean Architecture,Hexagonal Architecture,我正在设计一个运输应用程序,并尝试使用干净的体系结构。我试图找出在哪里保存装运对象的状态,这样我就不必每次用户单击UI中的按钮时都重新实例化一个新对象。这里是流程图 用户在UI中输入交货编号 UI控制器处理UI事件并实例化用例交互器的实例 A.中的存储库实例传递到用例交互器的构造函数中 用例交互器通过调用工厂来实例化装运实例(例如,按交货创建交货)。工厂调用存储库从数据库收集数据 交付数据在UI上填充 用户然后单击一个报价按钮 UI控制器处理按钮点击事件并调用用例交互器的RATE_QUOTE方法

我正在设计一个运输应用程序,并尝试使用干净的体系结构。我试图找出在哪里保存装运对象的状态,这样我就不必每次用户单击UI中的按钮时都重新实例化一个新对象。这里是流程图

  • 用户在UI中输入交货编号
  • UI控制器处理UI事件并实例化用例交互器的实例 A.中的存储库实例传递到用例交互器的构造函数中
  • 用例交互器通过调用工厂来实例化装运实例(例如,按交货创建交货)。工厂调用存储库从数据库收集数据
  • 交付数据在UI上填充
  • 用户然后单击一个报价按钮
  • UI控制器处理按钮点击事件并调用用例交互器的RATE_QUOTE方法 A.用例交互者是否需要像步骤#3中那样再次调用装运工厂,或者用例交互者是否可以获得在步骤#3中已经创建的装运对象的实例
  • 费率显示在UI上
  • 用户然后单击“处理装运”按钮
  • UI控制器处理按钮点击事件,并调用用例交互器的流程装运方法 A.用例交互者是否需要像步骤#3中那样再次调用装运工厂,或者用例交互者是否可以获得在步骤#3中已经创建的装运对象的实例
  • 装运对象的状态应该是UI控制器、用例交互器或存储库上的实例变量吗?理想情况下,我希望将其保存在某个位置,这样就不需要每次用户单击UI上的按钮时都不断创建新对象

    提前谢谢你

    DDD存储库可以是有状态的吗

    是的,绝对是——这是原始描述的一部分

    存储库将特定类型的所有对象表示为概念集(通常是模拟的)。它的行为就像一个集合,只是具有更复杂的查询功能。。。。对于需要全局访问的每种类型的对象,创建一个对象,该对象可以提供该类型所有对象的内存中集合的幻觉

    换句话说,重点是将应用程序组件与集合的实现细节分开。据应用程序所知,存储库可以实现为有状态、内存中的键/值存储

    理想情况下,我希望将其保存在某个位置,这样就不需要每次用户单击UI上的按钮时都不断创建新对象

    为了使您的代码易于理解,您可能每次都应该创建一个新对象,并且只有在您有明确的业务案例时才能处理缓存的复杂性

    也就是说,存储库的实现绝对没有理由不包含最近使用的对象的缓存。您只需要愿意投资于缓存失效策略

    记住,菲尔·卡尔顿几年前教过我们

    在计算机科学中只有两件困难的事情:缓存失效和命名


    理论上,根据定义,它总是有状态的。您询问存储库在加载/存储聚合时是否可以使用缓存。是的,但是。缓存是一件复杂的事情,除非必要,否则应该避免

    在这种特殊情况下,使用缓存会损害应用程序的水平可伸缩性。很难有多个实例。很难在数据库/持久性级别使用乐观锁定,加载聚合时需要正确设置聚合的版本(它必须是最大的),否则预期的版本(加载的版本+1)不匹配。换句话说,正如@VoiceOfUnreason所说,很难以有效的方式使缓存失效

    因此,如果您愿意放松水平可伸缩性,那么是的,您可以缓存聚合


    注意:这不适用于事件源聚合存储库。在这种情况下,您可以将快照保留在内存中,但仍可以触摸/查询事件存储以获取新事件。

    谢谢您提供的信息。在用例交互器中存储对象是一种选择吗?或者这会违反清洁建筑原则吗?@TonyRaimo它不会违反任何东西。在这种情况下,交互者的行为就像一个缓存。我要补充的是,您的实际存储库实现不应该包括任何缓存。而是使用decorator模式来包含缓存。这个装饰器将包装实际的实现(可能是构造函数注入),然后执行缓存。您的用例仍然需要,比如,
    IShipmentRepository
    ,但是您需要实例化“包装器”并传递存储库实例。通过这种方式,您可以保持存储库的干净。