Domain driven design 如何为实体建模';DDD中的当前状态
我正试图抓住DDD背后的想法,并将其应用到我们的一个宠物项目中,我有一些问题,希望在座的人能够回答 该项目是一个文件管理系统。我们的系统处理的两个概念是特定的问题:一个是Domain driven design 如何为实体建模';DDD中的当前状态,domain-driven-design,Domain Driven Design,我正试图抓住DDD背后的想法,并将其应用到我们的一个宠物项目中,我有一些问题,希望在座的人能够回答 该项目是一个文件管理系统。我们的系统处理的两个概念是特定的问题:一个是文档,另一个是文档状态 文档具有许多属性(如标题、作者等)。用户可以在文档的整个生命周期内更改文档的任何属性 文件可能在任何时候处于特定状态,例如新的,正在修订中,修订的,批准的等。对于每个状态,我们需要知道是谁更改了该状态 我们需要能够根据文档状态查询系统。一个示例查询是“获取处于revisited状态的所有文档” “获取用户
文档
,另一个是文档状态
文档
具有许多属性(如标题、作者等)。用户可以在文档的整个生命周期内更改文档的任何属性
文件
可能在任何时候处于特定状态,例如新的
,正在修订中
,修订的
,批准的
等。对于每个状态,我们需要知道是谁更改了该状态
我们需要能够根据文档状态查询系统。一个示例查询是“获取处于revisited
状态的所有文档”
“获取用户X已更改其状态的所有文档”
在同一事务中,唯一需要更改文档
和文档状态
的时间是创建文档
时(创建文档,同时为其指定状态为新建
)
对于所有其他时间,用户界面允许更新其中一个,但不能同时更新两个(即,您可以更改文档的属性,如作者,但不能更改其状态),或者您可以更新其状态(从新建
到修订版下
),但不能更新其属性
我认为我们可以安全地考虑到<代码>文档<代码>是一个实体和一个聚合根。
我们对什么是DocumentStatus
感到困惑。一个选项是使其成为文档
集合的值对象部分
另一种选择是使其成为一个实体,并成为其自身聚合的根
我们还想提到,我们考虑了各种DDD文档中描述的CQR,但我们认为这太麻烦了,特别是考虑到我们需要对文档状态执行查询
任何提示或想法都会受到欢迎。如果只记录当前状态,那么这很可能是一个价值对象
由于您正在将更多符合条件的数据(如果不是标识的话)组合到其中,并且您也打算查询这些数据,因此在我看来,好像noDocumentStatus
与另一个类似,所以值对象没有多大意义,是吗
它由
- 文件
- 作者
- 发生的时间
此外,它在前面的<代码>文档状态> /代码>中更具意义(如果您考虑更多的状态而不仅仅是代码>新的< /代码>和<代码> UnthUp修订< /COD>)。p>
对我来说,这显然排除了将
DocumentStatus
建模为值对象的可能性
就状态作为DocumentStatus
的属性而言,遵循一切都是对象的概念(目前正在阅读David West的对象思想),那么这当然可以建模为价值对象
接着 领域
您说您需要能够看到过去的状态更改,因此状态历史成为一个域概念。一个简单的解决方案如下:
- 在
文档
实体中定义状态历史记录
李>
StatusHistory
是StatusUpdate
值对象的列表
状态历史记录
中的第一个元素始终反映当前状态-确保在创建文档
实体时将初始状态添加为状态更新
值对象
根据状态历史所需的额外逻辑,考虑为历史本身创建一个专用的值对象(甚至实体)。
坚持不懈
您并没有说您的持久性层是什么样子的,但我认为对StatusHistory
列表的第一个元素创建查询应该可以使用每种持久性机制。例如,使用map reduce数据存储,创建一个由Document.StatusHistory[0]
索引的视图,并使用该视图实现所需的查询。您是要记录所有状态转换还是只记录当前状态?我们将记录任何状态更改。我们记录新状态、请求者、更改原因和时间戳。因此,每个文档将有多个状态。当前状态将是最后一次输入的状态。确定,但StatusHistory是单独的聚合还是与文档相同的聚合?我这样问是因为除了创建(您必须在同一事务中创建文档和状态历史记录)之外,在所有其他情况下,这两个都会分别更新。我还需要查找哪些属性来确定它们是否属于同一聚合的一部分?这取决于影响文档和状态历史的不变量。如果您需要在这两个变量之间强制执行不变量以保持一致,那么它们将合并在一个集合中。只有当它们能够以最终一致的方式协作时,才能将它们分开。@如果我理解得很好,可以通过引入DocumentStatusChanged域事件将它们分开,StatusHistory可以处理该事件并将其转换为StatusUpdate值对象/实体。