【问题标题】:How to reference AggregateRoot internal entity data in DDD如何在 DDD 中引用 AggregateRoot 内部实体数据
【发布时间】:2015-11-09 19:14:51
【问题描述】:

我对 DDD 的理念很感兴趣,但我对封装和保护 AggregateRoot 内部实体的概念以及如何引用它们有一些疑问。我创建了一个简单的示例(如果域设计不好,请不要打我,这只是一个澄清问题的示例)

// can be referenced from outside, is aggregate root
public class Library : AggregateRoot
{
   IList<Shelf> shelfs { get; }
}

// can be referenced from outside, is aggregate root
public class Shelf : AggregateRoot
{
   Book GetBookById(Guid Id) {...}
}

// should be accessed through Shelf, not referenced outside the context
public class Book : Entity<Guid>
{
   Guid Id { get; } // or something else uniqe, e.g. ISBN
}

// how to reference a book here?
// I think, I should not use Id because this is internal and
//only valid for Shelf Aggregate (but I can't have a second one of this book)
public class Lending : AggregateRoot
{
   // feels wrong because of passing internals from Shelf
   Guid LendedBook { get; set; }

   // should I Clone() an object with unique identity, is this allowed in DDD?
   Book LendedBook { get; set;}

   // create separate type for lending (but what should this type cointain)
   LendedBookInfo LendedBook { get; set;}
}

希望得到一个明确的答案,因为大多数示例只是关于 ValueObjects(这很简单,因为它们无论如何都会被复制而没有真正被引用)。 我在示例中使用了 C# 样式的代码,但也欢迎任何其他编程语言或伪代码作为答案。

【问题讨论】:

  • 在现实世界的领域中,您很少需要引用其 AR 之外的实体,如果您需要,那么它可能表明该概念不是实体而是 AR 本身。例如,为什么 Book 会在这里成为 Shelf 的实体?不能将一本书移到另一个书架上吗?一本书可能是您的示例域中的 AR,然后您的问题就消失了,因此您的问题的前提有点缺陷。
  • 但是,我不认为禁止从其 AR 外部保留实体的 id 引用,只是 id 没有上下文是无用的,因此您还必须保留对 AR id 的引用.另请记住,AR 应仅通过 id 引用其他 AR,并且域模型并不意味着用于 UI 查询和报告。
  • @palx 这个例子设计得不好,因为它不是这里的重点……只是为了说明问题。
  • 我知道,这就是我写这些 cmets 的原因。我第二条评论的第一句话回答了你的问题。

标签: entity domain-driven-design aggregateroot design-principles


【解决方案1】:

您的外部 ID 使用示例

Guid LendedBook { get; set; }

没问题。为了使模型更明确,您可以做的是创建一个值对象BookId 并将其用于参考书籍。值对象BookId 是一个上下文范围的概念,即不是特定聚合的本地概念。

除此之外,您可能不希望公共 setter 或 IList 作为模型中的返回类型。但我想这只是一个例子,并不是这里真正的问题。

【讨论】:

  • 但是使用 Book 的 Guid Id 意味着如果 Shelf 也没有被引用,Book 需要是一个 AggregateRoot(具有全局唯一的 id 含义)。否则 id 不是唯一的,是 Shelf AggregateRoot 的内部概念。
【解决方案2】:

在 DDD 中,对现实世界进行建模从来都不是一件坏事。如果您与该领域的领域专家(图书馆员)交谈,他们可能拥有可以帮助您为领域建模的术语和工作流程。

例如,他们可能会使用“书票系统”谈论“借书”,当他们想按书名查找书籍时,他们可能会查看“书名目录”。

这可能会导致您有一个带有LendBook(lender, book) 方法的BookTicketService 类的设计,这可能会导致在BookTicketSystem 中记录一个条目。或具有SearchByTitle(title) 方法的TitleCatalogueService 类。或者当图书馆接受一本新书进入图书馆时,它的记录可能会在AccessionRegister等中。

如果您使用这种普遍存在的语言对您的图书馆进行建模,那么图书馆领域的其他人可以更轻松地获取您的软件,最重要的是,它允许软件开发人员与图书馆员讨论他们的需求,而无需使用软件开发术语。

我会在 Google 上搜索一些内容,例如 “如何创建图书馆”“图书馆术语表”,并尝试使用您找到的一些语言和流程进入您的软件。人们已经在运行功能齐全的图书馆,拥有数以万计的书籍和出借人。从理论上讲,您需要做的就是了解他们如何做到这一点、他们使用的术语以及应该可以在软件中对其进行建模。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 2022-06-15
    • 1970-01-01
    相关资源
    最近更新 更多