Domain driven design DDD:聚合根
我需要帮助找到我的聚合根和边界 我有3个实体:计划、计划角色和计划培训。每个计划可以包括许多计划角色和计划培训 解决方案1:起初我认为计划是聚合根,因为PlannedRole和PlannedTraining在计划的上下文中没有意义。他们总是在计划之内。此外,我们有一条业务规则,规定每个计划最多可以有3个计划角色和5个计划培训。所以我认为通过将计划指定为聚合根,我可以强制执行这个不变量 但是,我们有一个搜索页面,用户在其中搜索计划。结果显示了计划本身的一些属性(并且没有计划的角色或计划的培训)。我想如果我必须加载整个聚合,它会有很多开销。有近3000个计划,每个计划可能有几个孩子。将所有这些对象加载到一起,然后在搜索页面中忽略PlannedRoles和PlannedTrainings对我来说没有意义 解决方案2:我刚刚意识到用户需要另外两个搜索页面,在那里他们可以搜索计划的角色或计划的培训。这让我意识到他们试图独立访问这些对象,并且“脱离”计划的上下文。所以我认为我的初始设计是错误的,这就是我提出这个解决方案的原因。所以,我认为这里有3个聚合,每个实体1个 这种方法使我能够独立地搜索每个实体,还解决了解决方案1中的性能问题。但是,使用这种方法,我无法强制执行前面提到的不变量 还有一个不变量表示,只有当计划处于某一状态时,才能对其进行更改。所以,我不能在一个不处于该状态的计划中添加任何PlannedRoles或PlannedTraining。同样,我不能用第二种方法强制执行这个不变量 如有任何建议,将不胜感激 干杯,Domain driven design DDD:聚合根,domain-driven-design,aggregate,aggregateroot,aggregates,Domain Driven Design,Aggregate,Aggregateroot,Aggregates,我需要帮助找到我的聚合根和边界 我有3个实体:计划、计划角色和计划培训。每个计划可以包括许多计划角色和计划培训 解决方案1:起初我认为计划是聚合根,因为PlannedRole和PlannedTraining在计划的上下文中没有意义。他们总是在计划之内。此外,我们有一条业务规则,规定每个计划最多可以有3个计划角色和5个计划培训。所以我认为通过将计划指定为聚合根,我可以强制执行这个不变量 但是,我们有一个搜索页面,用户在其中搜索计划。结果显示了计划本身的一些属性(并且没有计划的角色或计划的培训)。我
莫斯在设计我的模型时,我也遇到了类似的问题,我问了这个问题,我认为这个问题可能会对你有所帮助,特别是关于你的第一点 当涉及到搜索时,我不使用“模型”,而是使用返回“摘要”对象的专门搜索存储库。。。i、 e.“计划摘要”。这些对象只不过是信息对象(可以被认为更像报告),并没有在事务意义上使用——我甚至没有在我的模型类库中定义它们。通过创建这些专用存储库和类型,我可以实现高性能的搜索查询,这些查询可以包含分组数据(如PlannedTraining计数),而无需在内存中加载聚合的所有关联。一旦用户在UI中选择了其中一个摘要对象,我就可以使用该ID获取实际的模型对象并执行事务操作和提交更改 因此,对于您的情况,我将为所有三个实体提供这些专门的搜索存储库,当用户希望对其中一个实体执行操作时,您总是获取它所属的计划集合 通过这种方式,您可以进行性能搜索,同时仍然使用所需的不变量维护单个聚合 编辑-示例: 好的,我想实现是主观的,但这就是我在应用程序中处理它的方式,以“TeamMember”聚合为例。用C#编写的示例。我有两个类库:
- 模型
- 报告
public class TeamMemberSummary
{
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime DateOfBirth { get; set; }
public bool IsAvailable { get; set; }
public string MainProductExpertise { get; set; }
public int ExperienceRating { get; set; }
}
报表库还包含以下界面:
public interface ITeamMemberSummaryRepository : IReportRepository<TeamMemberSummary>
{
}
公共接口ITeamMemberSummaryRepository:IReportRepository
{
}
这是应用层(在我的例子中,恰好是WCF服务)将使用的接口,并将通过我的IoC容器(Unity)解决实现问题。IReportRepository与基本ReportRepositoryBase一样位于Infrastructure.Interface库中。所以我的系统中有两种不同类型的存储库-聚合存储库和报告存储库
然后在另一个库Repositories.Sql中,我实现了:
public class TeamMemberSummaryRepository : ITeamMemberSummaryRepository
{
public IList<TeamMemberSummary> FindAll<TCriteria>(TCriteria criteria) where TCriteria : ICriteria
{
//Write SQL code here
return new List<TeamMemberSummary>();
}
public void Initialise()
{
}
}
公共类TeamMemberSummaryRepository:ITeamMemberSummaryRepository
{
公共IList FindAll(TCriteria标准),其中TCriteria:ICriteria
{
//在此处编写SQL代码
返回新列表();
}
公开无效初始化()
{
}
}
因此,在我的应用层:
public IList<TeamMemberSummary> FindTeamMembers(TeamMemberCriteria criteria)
{
ITeamMemberSummaryRepository repository
= RepositoryFactory.GetRepository<ITeamMemberSummaryRepository>();
return repository.FindAll(criteria);
}
public IList FindTeamMembers(TeamMemberCriteria)
{
ITeamMemberSummary存储库
=RepositoryFactory.GetRepository();
返回repository.FindAll(标准);
}
然后,在客户端中,用户可以选择这些对象中的一个,并在应用层中对其中一个对象执行操作,例如:
public void ChangeTeamMembersExperienceRating(Guid teamMemberID, int newExperienceRating)
{
ITeamMemberRepository repository
= RepositoryFactory.GetRepository<ITeamMemberRepository>();
using(IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
{
TeamMember teamMember = repository.GetByID(teamMemberID);
teamMember.ChangeExperienceRating(newExperienceRating);
repository.Save(teamMember);
}
}
public void ChangeTeamMembersExperienceRating(Guid teamMemberID,int newExperienceRating)
{
ITeamMemberRepository
=RepositoryFactory.GetRepository();
使用(IUnitOfWork unitOfWork=UnitOfWorkFactory.CreateUnitOfWork())
{
TeamMember TeamMember=repository.GetByID(teamMemberID);
团队成员。变更体验培训(新体验培训);
保存(团队成员);
}
}
这里真正的问题是SRP违规。应用程序的输入部分与输出部分发生冲突
坚持第一个解决方案(计划==聚合根)。人为地将实体(甚至是价值对象)提升为聚合根会扭曲整个域模型并破坏一切
您可能希望查看所谓的(命令查询责任分离)体系结构,它非常适合解决这个特定问题。作者:马克·尼霍夫。这是一个不错的列表。这是t