【问题标题】:How To Determine Aggregate Root - Domain Driven Design如何确定聚合根 - 领域驱动设计
【发布时间】:2013-06-09 11:27:17
【问题描述】:

我有一个聚合:用户。
我将如何确定它的聚合根?

因为我有:

   +User(folder)
     - User(Abstract Class)
     * Administrator(Concrete inherits from User)
     * Manager(Concrete inherits from User)
     * Maintenance(Concrete inherits from User)

我还必须为每个用户类(管理员、经理、维护)创建一个存储库吗? 还是只创建一个使用抽象类(用户)的存储库?

【问题讨论】:

  • 您可能应该阅读 Vaughn Vernon 关于有效聚合根设计的论文:dddcommunity.org/library/vernon_2011
  • 我不知道User 在哪个域中,但最好叫它UserRole。在许多域中,一个用户可以同时拥有多个角色,并且角色分配会随着时间而变化。

标签: c# oop repository domain-driven-design domain-model


【解决方案1】:

您的问题有两个相关的部分: 首先,我认为您对聚合和聚合根的概念并不准确。因此,重要的是在继续之前让它们正确。

当你有继承关系时,这不是一个聚合问题。聚合适用于组合。原因如下:

让我们举个例子。你有一个抽象类用户,然后你有这些用户的专业化:管理员、经理、维护。现在,这四个不是聚合-聚合-根关系。但是,它们都是聚合根。或者换句话说,每个都是聚合根。

从用户开始,假设这是聚合的聚合根。现在,因为管理员是用户,您可以用管理员替换用户,它成为根。其他专业也一样。

关键是要了解管理员、经理、维护是同一聚合中用户的替换。它们不是用户的对象值

您问题的第二部分是关于实施的。是为每个子类型实现单独的存储库类还是为所有子类型实现一个单独的存储库类。这个问题的答案取决于您的应用程序的详细信息、您使用的工具类型等。没有硬性规定可以选择两种方式中的哪一种。例如,如果您的子类型只有几个属性不同,最好将它们全部放在单个表和单个存储库中,否则有单独的存储库。例如,Hibernate 框架允许两种方式中的任何一种,由开发人员/设计人员选择。

但是,同样,关键是要考虑这个问题,将其视为继承(它是)而不是聚合/聚合根问题。

【讨论】:

  • 嗨 Nazar...感谢您帮助我.. 所以在这种情况下,我只需将每个专业化设置为聚合根,然后为每个专业化使用 1 个存储库,因为只有少数几个(例如2 或 3) 每个专业的属性差异。但是由于我的 User 是一个抽象类,所以每次我从存储库中查询一条记录时,我都需要具体确定它是什么专业。我对吗?但是我需要为我的用户聚合创建一个工厂类吗?
  • 哦,我正在使用实体框架顺便说一句.. 但我的域模型是持久性无知.. 只知道 IUserRepository,IWhateverRepository...谢谢:)
  • 我使用了 Hibernate 框架和一个称为 Generic Dao Pattern (GDP) 的模式来处理这样的持久性。使用 GPD 的想法是使用 Java 的泛型。我不确定这如何转化为 C#。也许 C# 的人可以对此发表评论。
  • 是的..检查了... C#有通用接口
【解决方案2】:

首先,如果用户是实体,则取决于您的域。例如,在视频租赁商店中,用户是一个实体,可能是聚合根的良好候选者。但是,如果您要设计一个系统来进行招聘。那么也许用户只是为了登录系统。所有用户都可以做任何事情,并且都具有相同的角色 - 招聘人员。那么也许用户更像是一个基础设施,用户可能只能由一个用户ID代表......在候选人中的某个地方。这完全取决于用户和上下文。

关于继承和存储库:继承是一个很重要的介绍。它可能会导致问题,但也可以降低复杂性。这取决于您是否有许多可以放在基类 User 中的共同行为。然后你可以从多态中得到很多,让只有一个 UserService。然后,UserService 可以在需要时使用 AdministratorRepository 或 ManagerRepository。但是检查你是否可以通过组合而不是继承来解决这个问题。它不会产生太多的耦合。当您想使用新的子类进行扩展时,它会增加一点复杂性。

【讨论】:

  • 感谢您的建议 Magnus... 好的,所以我的域将保持不变.. 并且有一个 UserService 类使用:IAdministratorRepository、IManagerRepository、ICashierRepository.. 很好.. 但很多基础设施存储库代码中的额外工作,因为您必须为每个存储库实现一个不同的存储库.. 但它会起作用.. 在我的数据库模式中只有一个表:存储的用户:管理员、经理、收银员..etc 及其字段仅当字段特定于某个用户但未使用时才允许为 null..
  • 虽然我可能必须为用户添加一个工厂类,这是我的强制转换/多态性将起作用的地方。每个用户(管理员、经理等)都有自己不同的字段和常见的字段被放置在用户(抽象类)中..似乎我不会为用户聚合有一个特定的聚合根,因为用户可以是:管理员、经理、收银员..等等我会怎么做?
  • 不确定我是否遵循您的问题。你还在为你的 AR 挣扎……我认为如果可以的话,你应该远离继承。但如果你必须要我投票支持拥有一个 AR 用户。然后您面临两个选择,让客户端执行从用户到管理员的转换,或者您可以拥有一个功能:执行转换的管理员 UserRepository.GetAdministrator(int userId)。问题是您需要确保 userId 是管理员 id,否则它将成为 BOOM。如果您将 Nhibernate 与鉴别器列一起使用,您可能会在选择非管理员实例时遇到这种情况
  • 这可以通过使用特殊的 id 序列来解决,这样您就可以确定某些 id 是管理员 id 或其他 id 是经理 id...
  • 但正如我之前提到的......如果可以的话,真的尽量避免在域模型中继承。它为您省去了很多麻烦
猜你喜欢
  • 2010-11-01
  • 1970-01-01
  • 2010-11-30
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 1970-01-01
  • 2013-09-16
相关资源
最近更新 更多