1

上下文:
我有一个实体书。一本书可以有一个或多个描述。描述是值对象。

问题:
一个描述可以比另一个描述更具体。例如,如果描述包含书的内容和封面的外观,那么它比仅讨论封面外观的描述更具体。我不知道如何对此建模以及如何让存储库保存它。了解这些关系不是本书或本书描述的责任。其他一些对象可以处理此问题,然后要求存储库保存关系。但是 BookRepository.addMoreSpecificDescription(Description, MoreSpecificDescription) 对于存储库来说似乎很难保存。

这样的事情在 DDD 中是如何处理的?

4

3 回答 3

7

其他两个答案是一个方向(+1 btw)。我是在您对原始问题进行编辑后进来的,所以这是我的两分钱......

我将值对象定义为具有两个或多个可以(并且是)在其他实体之间共享的属性的对象。它们只能在单个聚合根中共享,这也很好。只是他们可以(并且是)共享的事实。

要使用您的示例,您将“描述”定义为值对象。这告诉我可以在几本书之间共享具有多个属性的“描述”。在现实世界中,这是没有意义的,因为我们都知道每本书都有由作者或出版者撰写的独特描述。呵呵。因此,我认为描述并不是真正的值对象,但它们本身是您的书聚合根实体边界中的附加实体对象(您可以在单个聚合根的实体中拥有多个实体)。即使是重新发行的书籍、较新的修订版等,描述这种微小变化的描述也略有不同。

我相信这回答了你的问题 - 制作描述实体对象并将它们保护在你的主要 Book Entity Aggregate Root 后面(例如 Book.GetDescriptions()...)。这个答案的其余部分解决了我如何处理存储库中的值对象,对于阅读这篇文章的其他人......

为了将值对象存储在存储库中并检索它们,当我从“数据库优先”建模方法切换到 DDD 方法时,我们开始涉足我与自己搏斗的同一领域。我自己与这个有关,关于如何在数据库中存储一个值对象,并在没有身份的情况下检索它。直到我退后一步,意识到我在做什么......

在域驱动设计中,您正在对域中的值对象进行建模 - 而不是您的数据存储。这是关键短语。这意味着您没有将值对象设计为在数据存储中存储为独立对象,您可以随心所欲地存储它们!

让我们以值对象的常见 DDD 示例为例,即 Address()。DDD 提出邮寄地址是完美的值对象示例,因为值对象的定义是一个对象,其属性汇总以创建对象的唯一性。如果一个属性发生变化,它将是一个不同的值对象。并且相同的值对象 9teh 其属性的总和)可以在其他实体之间共享。

邮寄地址是一个位置,是地球上特定位置的长/纬度。多个人可以住在该地址,当有人搬家时,占用相同邮寄地址的新人现在使用相同的值对象。

所以,我有一个 Person() 对象和一个 MailingAddress() 对象,其中包含地址信息。它通过 get/update/create 方法/服务在我的 Person() 聚合根目录后面受到保护。

现在,我们如何存储它并在同一个家庭的人之间共享?啊,这就是 DDD - 您不是直接从 DDD 对数据存储进行建模(尽管这样会很好)。话虽如此,您只需创建一个显示您的 Person 对象的 Table ,其中包含您的邮寄地址的列。您的存储库的工作是将该信息从数据存储重新水合回您的 Person() 和 MailingAddress() 对象,并在创建/更新操作期间将其拆分。

是的,您的数据存储中现在有重复的数据。三个具有相同邮寄地址的 Person() 实体现在都拥有该值对象数据的三个单独副本 - 这没关系!值对象意味着很容易被复制和破坏。“复制”是 DDD 剧本中的最佳词。

总而言之,域驱动设计是关于对域进行建模以表示对象的实际业务使用。您分别为 Person() 实体和 MailingAddress 值对象建模,因为它们在您的应用程序中的表示方式不同。您将它们保存为复制数据,即与您的 Person 表在同一表中的附加列。

以上都是严格的DDD。但是,DDD 只是“建议”,而不是生活的规则。这就是为什么你可以自由地做我自己和其他许多人所做的事情,一种松散的 DDD 风格。如果您不喜欢复制的数据,您唯一的选择是您可以为 MailingAddress() 创建一个单独的表并在其上粘贴一个 Identity 列,然后更新您的 MailingAddress() 对象以使其现在具有该身份 -知道您仅使用该身份将其链接到共享它的其他 Person() 对象(我个人喜欢第三个多对多关系表,以保持查询速度)。您将屏蔽该身份(即内部修饰符)以免暴露在聚合根/域之外,因此其他层(例如应用程序或 UI)不知道 MailingAddress 的身份列,如果可能的话。另外,我会为 MailingAddress 创建一个专用存储库,并使用您的 PersonService 层将它们组合成正确的对象 Person.MailingAddress()。

对不起,咆哮... :)

于 2009-12-22T00:33:09.360 回答
4

首先,我认为评论应该是实体。

其次,您为什么要尝试对评论之间的关系进行建模?我看不出他们之间有自然的关系。“比更具体”太模糊,无法用作关系。

如果您难以对情况进行建模,则表明可能没有关系。

于 2009-12-18T20:31:21.677 回答
1

我同意杰森。我不知道你让评论价值对象的理由是什么。

我希望 BookReview 具有 BookReviewContentItems 以便您可以在 BookReview 上有一个方法来调用以确定它是否足够具体,该方法根据查询其内容项的集合来决定。

于 2009-12-18T20:37:21.933 回答