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

时间:2015-11-09 19:14:51

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

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

2 个答案:

答案 0 :(得分:1)

您的外部身份证使用示例

BookId

很好。如何使模型更加明确,您可以做的是创建一个值对象BookId并使用该对象来引用书籍。然后,值对象IList是一个上下文范围的概念,即不是特定聚合的本地概念。

除此之外,您可能不希望公共设置者或 String text = ""; text += "<html><body>"; text += "<a href=\"" + CallAPI.mBaseUrl + "/uploads/media/default/0001/01/021ffb272477a45c032c178de0160e352134f8dd.png" + "\">" + "test" + "</a>"; text += "</body></html>"; Log.d("FragmentFicheProduit", text); Utils.openApplication(rootView.getContext(), "com.lotus.sync.traveler", getResources().getString(R.string.information_nom_produit) + " " + produit.getNom_produit(), text, null); public static void openApplication(final Context context, String packageN, String subject, String text, ArrayList<Contact> contactArrayList) { Intent i = new Intent(Intent.ACTION_SEND); i.setType("text/html"); if (i != null) { if (subject != null) i.putExtra(Intent.EXTRA_SUBJECT, subject); if (text != null) i.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(text)); if (contactArrayList != null) { String[] tmp = new String[contactArrayList.size()]; for (int y = 0; y < contactArrayList.size(); y++) { tmp[y] = contactArrayList.get(y).getEmailaddress1(); } i.putExtra(android.content.Intent.EXTRA_EMAIL, tmp); } final PackageManager pm = context.getPackageManager(); final List<ResolveInfo> matches = pm.queryIntentActivities(i, 0); ResolveInfo best = null; for (final ResolveInfo info : matches) { if (info.activityInfo.packageName.endsWith(".traveler")) best = info; } if (best != null) i.setClassName(best.activityInfo.packageName, best.activityInfo.name); context.startActivity(i); } else { try { context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageN))); } catch (android.content.ActivityNotFoundException anfe) { context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + packageN))); } } } 作为模型中的返回类型。但我想这只是一个例子而不是这里的问题。

答案 1 :(得分:1)

在DDD中,对现实世界进行建模绝非易事。如果您与该域中的域专家(图书管理员)交谈,他们可能拥有可帮助您为域建模的术语和工作流程。

例如,他们可能会谈论&#34;出借一本书&#34;使用&#34;预订票系统&#34;当他们想要按照标题找到一本书时,他们可能会看到&#34;标题目录&#34;。

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

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

我在谷歌的一些事情,如&#34;如何启动图书馆&#34; &#34;图书馆词汇表&#34; 并尝试将您找到的一些语言和流程引入您的软件。人们已经拥有功能齐全的图书馆,拥有成千上万的图书和贷方。理论上,您需要做的就是了解他们如何做到这一点,他们使用的术语以及应该可以用软件对其进行建模。