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

Can a DDD repository be stateful?

我正在设计一个交付应用程序并尝试使用 Clean Architecture。我试图找出保存 Shipment 对象状态的位置,这样我就不必在每次用户单击 UI 中的按钮时重新实例化一个新对象。这是流程。

  1. 用户在 UI
  2. 中输入送货单号
  3. UI 控制器处理 UI 事件并实例化用例交互器的实例 一个。一个存储库实例传入了用例交互器的构造函数
  4. 用例交互器通过调用工厂来实例化 Shipment 实例(例如 CREATE_BY_DELIVERY)。工厂调用存储库从数据库中收集数据。
  5. 投放数据已填充到 UI
  6. 然后用户单击“报价”按钮
  7. UIController处理按钮点击事件,调用Use Case Interactor的RATE_QUOTE方法 一个。用例交互器是否需要像步骤 #3 中那样再次调用 Shipment 工厂,或者用例交互器是否可以获取已在步骤 #3 中创建的 Shipment 对象的实例?
  8. 费率显示在 UI
  9. 然后用户点击处理装运按钮
  10. UIController处理按钮点击事件,调用Use Case Interactor的PROCESS_SHIPMENT方法 一个。用例交互器是否需要像步骤 #3 中那样再次调用 Shipment 工厂,或者用例交互器是否可以获取已在步骤 #3 中创建的 Shipment 对象的实例?

货运对象的状态应该是 UI 控制器、用例交互器或存储库上的实例变量吗?理想情况下,我想将它保存在某个地方,这样我就不需要在每次用户单击 UI.

上的按钮时都创建一个新对象

提前致谢!

Can a DDD repository be stateful?

是的,绝对是 - 这是原始描述中要点的一部分

A REPOSITORY represents all objects of a certain type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying capability.... For each type of object that needs global access, create an object that can provide the illusion of an in memory collection of all objects of that type.

换句话说,重点是将应用程序组件与集合的实现细节分开。就应用程序而言,存储库可以实现为内存中的有状态 key/value 存储。

Ideally, I'd like to save it somewhere so I don't need to keep creating a new object every time a user clicks a button on the UI.

为了让您的代码易于理解,您应该可能每次都创建一个新对象,并且只有在您清楚地了解缓存时才处理复杂的缓存商业案例。

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

记住,Phil Karlton 多年前教过我们

There are only two hard things in Computer Science: cache invalidation and naming things.

从理论上讲,它根据定义始终是有状态的。您问的是 loading/storing 聚合时存储库是否可以使用缓存。所以是的,但是。缓存是一件复杂的事情,除非必要,否则应该避免。

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

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

P.S。这不适用于事件源聚合存储库。在这种情况下,您可以将快照保留在内存中,但仍然 touch/query 新事件的事件存储。