DDD中如何引用AggregateRoot内部实体数据

How to reference AggregateRoot internal entity data in DDD

我对 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# 风格的代码,但也欢迎任何其他编程语言或伪代码作为答案。

您的外部 ID 使用示例

Guid LendedBook { get; set; }

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

除此之外,您可能不希望 public setter 或 IList 作为 return 类型输入您的模型。但我想这只是一个例子,并不是真正的问题。

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

例如,他们可能会使用 "book ticket system" 谈论 "lending a book",当他们想按书名查找一本书时,他们可能会查看 "title catalogue"。

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

如果您使用这种无处不在的语言为您的图书馆建模,它可以让图书馆领域的其他人更轻松地使用您的软件,最重要的是,它允许软件开发人员与图书馆员讨论他们的需求,而无需使用软件开发术语。

我会 Google 一些类似 "how to start a library""library glossary of terms" 的东西,然后尝试将您找到的一些语言和流程带入您的软件中。人们已经 运行 功能齐全的图书馆,拥有数以万计的图书和出借人。从理论上讲,您需要做的就是了解他们是如何做到这一点的,他们使用的术语以及应该可以在软件中对其进行建模。