Domain driven design 简单聚合根和存储库

Domain driven design 简单聚合根和存储库,domain-driven-design,repository,aggregate,Domain Driven Design,Repository,Aggregate,我是许多试图理解聚合根概念的人之一,我想我已经明白了! 然而,当我开始为这个示例项目建模时,我很快陷入了两难境地 我有两个实体ProcessType和Process。一个进程如果没有进程类型,就不可能存在,而进程类型有许多进程。因此,流程持有对类型的引用,没有它就无法存在 那么ProcessType是否应该是聚合根?通过调用processType.AddProcess(New Process()),可以创建新流程; 但是,我还有其他实体,它们只持有对流程的引用,并通过流程.type访问其类型。在

我是许多试图理解聚合根概念的人之一,我想我已经明白了! 然而,当我开始为这个示例项目建模时,我很快陷入了两难境地

我有两个实体
ProcessType
Process
。一个
进程
如果没有
进程类型
,就不可能存在,而
进程类型
有许多
进程
。因此,流程持有对类型的引用,没有它就无法存在

那么
ProcessType
是否应该是聚合根?通过调用
processType.AddProcess(New Process())
,可以创建新流程; 但是,我还有其他实体,它们只持有对
流程的引用,并通过
流程.type
访问其类型。在这种情况下,首先通过
ProcessType
是没有意义的


但是,聚合外部的AFAIK实体只允许持有对聚合根的引用,而不允许持有聚合内部的实体。所以我这里有两个聚合,每个聚合都有自己的存储库吗?

不是那么简单。ProcessType最像是一个知识层对象——它定义了一个特定的过程。另一方面,Process是ProcessType流程的实例。你可能真的不需要或不想要这种双向关系。Process可能不是ProcessType的逻辑子级。它们通常属于其他东西,如产品、工厂或序列

根据定义,删除聚合根时,也会删除聚合的所有成员。当您删除进程时,我严重怀疑您是否真的要删除ProcessType。如果删除了ProcessType,您可能希望删除该类型的所有进程,但这种关系已经不理想,而且一旦有了由ProcessType定义的历史进程,您就不会删除定义对象

我将从ProcessType中删除Processs集合,并找到一个更合适的父级(如果存在的话)。我会将ProcessType保留为Process的成员,因为它可能定义了Process。操作层(Process)和知识层(ProcessType)对象很少作为单个聚合工作,因此我希望流程是聚合根,或者可能找到作为流程父级的聚合根。那么ProcessType将是一个外部类。Process.Type很可能是多余的,因为您已经有了Process.ProcessType。把它扔掉

我有一个类似的医疗模式。有程序(操作层)和程序类型(知识层)。ProcedureType是一个独立类。过程是第三个对象相遇的子对象。Conference是过程的聚合根。过程引用了ProcedureType,但这是一种方式。ProcedureType是一个定义对象,它不包含过程集合

编辑(因为评论非常有限)

有一件事要牢记在心。许多人是DDD的纯粹主义者,对规则持坚决态度。然而,如果你仔细阅读埃文斯,他会不断地提出一种可能性,即通常需要权衡。他还不厌其烦地描述了逻辑性的、经过仔细思考的设计决策,而不是像团队这样为了方便而不理解目标或回避聚合之类的事情

重要的是理解和应用与规则相反的概念。我看到许多DDD将应用程序塞进不合逻辑和混乱的聚合中,原因无非是因为应用了关于存储库或遍历的文字规则,这不是DDD的意图,但它通常是许多人采取的过于教条的方法的产物

那么,这里的关键概念是什么:

聚合通过将许多对象的行为减少为关键参与者的更高级别行为,提供了一种使复杂系统更易于管理的方法

聚合提供了一种方法,以确保在逻辑且始终有效的条件下创建对象,同时在更新和删除过程中保留逻辑工作单元

让我们来考虑最后一点。在许多传统应用程序中,有人创建一组对象,但这些对象并没有完全填充,因为它们只需要更新或使用一些属性。下一个开发人员出现了,他也需要这些对象,而且有人已经在附近的某个地方为不同的目的制作了一套。现在这个开发人员决定只使用这些,但是他发现它们没有他需要的所有属性。因此,他添加了另一个查询并填写了更多的属性。最终是因为团队不坚持OOP,因为他们普遍认为OOP“对于现实世界来说是低效和不切实际的,并且会导致性能问题,例如创建完整对象来更新单个属性”。他们最终得到的是一个充满嵌入式SQL代码和对象的应用程序,这些代码和对象基本上是在任何地方随机实现的。更糟糕的是,这些对象是巴斯德化的无效代理。一个过程看起来是一个过程,但它不是,它是以不同的方式部分填充任何给定点,这取决于需要什么。结果是大量查询不断地以不同的程度部分填充对象,并且经常有许多无关的垃圾,如空检查,这些检查不应该存在,但却是必需的,因为对象从来都不是真正有效的,等等

聚合规则通过确保仅在某些逻辑点创建对象并始终使用一整套有效的关系和条件来防止这种情况。因此,现在我们已经完全了解了聚合规则的用途以及它们保护我们不受什么影响,我们还想了解,我们也不想滥用这些规则,创建奇怪的聚合,这些聚合不能反映我们的应用程序的真正意义,仅仅因为这些聚合规则存在
Public class Process
{
      Public Process()
      {

      }

      public ProcessType { get; }

}
public class Process
{
     public ProcessType { get; }
}
public class TeamMember : Person
{
    public Guid TeamMemberID
    {
        get { return _teamMemberID; }
    }

    public TeamMemberRoleType RoleType
    {
        get { return _roleType; }
    }

    public IEnumerable<AvailabilityPeriod> Availability
    {
        get { return _availability.AsReadOnly(); }
    }
}
public void CreateTeamMember(CreateTeamMemberCommand command)
{
    TeamMemberRoleType role = _lookupService.GetLookupItem<TeamMemberRoleType>(command.RoleTypeID);

    TeamMember member = TeamMemberFactory.CreateTeamMember(command.TeamMemberID,
                                                           role,
                                                           command.DateOfBirth,
                                                           command.FirstName,
                                                           command.Surname);

    using (IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
        _teamMemberRepository.Save(member);
}
ILookup<TeamMemberRoleType> roles = _lookupService.GetLookup<TeamMemberRoleType>();