【问题标题】:Aggregate root design and presentation layer聚合根设计和表示层
【发布时间】:2011-01-06 09:26:05
【问题描述】:

我想知道我的表示层的结构是否可以引导我设计聚合根。

让我们有一个实体 ProjectEntity 及其相关实体 ProjectMemberEntity (1:M)

页面结构如下:

页面顶部是ProjectEntity的表单

表单下方是一个显示 ProjectMemberEntity 列表的网格。

如果要添加新的 ProjectMember,用户必须到此页面并单击位于网格标题中的“添加新成员”按钮。编辑和删除也有相同的比喻。

我想知道这种行为/“页面结构”是否可以作为聚合根(项目实体)的提示

【问题讨论】:

    标签: domain-driven-design aggregateroot


    【解决方案1】:

    这肯定是一个提示。但没有更多。

    澄清实体关系的更好方法是询问领域专家:

    • 没有项目,项目成员是否有意义?
    • 会员可以参与多个项目吗?

    如果这些回答是肯定的,那么您很可能应该将项目成员建模为聚合根本身。否则 - 将其降级为一个没有项目就无法生存的实体。


    这里有一些代码可能会给你一些想法:

    public class Project:Root{
     private List _members;
     public IEnumerable<Member> Members{get {return _members;}}
     public string Name{get;private set;}
     public bool IsFinished{get;private set;}
     public bool FinishedOn{get;private set;}
     public Project(string projectName){
      _members=new List<Member>();
      Name=projectName;
     }
     public Member AssignMember(string memberName){
      var member=new Member(memberName);
      _members.Add(member);
      return member;
     }
     public void UnassignMember(string memberName){
      var member=_members.First(m=>m.Name==memberName);
      if(!member.HasCompletedAllTasks())
       throw new Exception
        ("Cannot unassign member with incompleted tasks!");
      _members.Remove(member);
     }
     public void AssignTaskToMember(string taskName, string memberName){
      var member=_members.First(m=>m.Name==memberName);
      member.AssignTask(taskName);
     }
     public void MemberHasCompletedTask(Member member, Task task){
      EnsureListContains(_members,member);
      EnsureListContains(member.Tasks,task);
      task.MarkAsCompleted();
     }    
     public void FinishProject(){
      if(_members.Any(m=>!m.HasCompletedAllTasks()))
       throw new Exception
        ("Can't finish project before members have completed all their tasks.");
      IsFinished=true;
      FinishedOn=DateTime.Now;
     }
     private void EnsureListContains<T>(IList<T> lst, T itm){
      if(!lst.Contains(itm)) throw new Exception();
     }
    }
    
    public class Member:Entity{
     public string Name{get;private set;}
     private List<Task> _tasks;
     public IEnumerable<Task> Tasks{get{return _tasks;}}
     internal Member(string memberName){
      Name=name;
      _tasks=new List<Task>();
     }
     internal void AssignTask(string taskName){
      _tasks.Add(new Task(taskName));
     }
     public bool HasCompletedAllTasks(){
      return _tasks.All(t=>t.IsCompleted);
     }
     public Task GetNextAssignedTask(){
      return _tasks.Where(t=>!t.IsCompleted)
        .OrderBy(t=>t.AssignedOn).First();
     }
    }
    
    public class Task:Entity{
     public string Name{get; private set;}
     public bool IsCompleted{get; private set;}
     public DateTime CompletedOn{get; private set;}    
     public DateTime AssignedOn{get; private set;}
     internal Task(string name){
      Name=name;
      AssignedOn=DateTime.Now;
     }
     internal void MarkAsCompleted(){
      if(IsCompleted) throw new Exception
       ("Task is already completed!");
      IsCompleted=true;
      CompletedOn=DateTime.Now;
     }
    }
    
    public class App{
     public static void Main(){
      var project=new Project
        ("Question: Aggregate root design and presentation layer");
      var me=project.AssignMember("Arnis Lapsa");
      project.AssignTaskToMember("Try to help user137348","Lapsa");
      var currentTask=me.GetNextAssignedTask();
      //SpamStackOverflow();
      project.MemberHasCompletedTask(me,currentTask);
      if(me.HasCompletedAllTasks()) project.Finish();
      else throw new Exception("Enough for today...");
     }
    }
    

    请注意,我对您的业务内容知之甚少。这只是一个即兴创作。 :)

    【讨论】:

    • “没有项目,项目成员是否有意义?”是什么意思? ?在数据库级别上创建了一个关系。所以每个项目成员都必须有一个父项目记录。还是您的意思是我还有一个必须分配给项目成员的TaskEntity。我猜在这种情况下项目成员实体可以没有项目,是这样吗?
    • @user137348 在做建模的时候,不要考虑数据库(你肯定会有那个级别的关系)。想想你的应用程序试图解决什么样的问题。这就是它被称为驱动的原因。如果您不需要成员独立,那么它就是一个实体。您将始终先创建项目并为其分配成员(没有项目就没有意义)。
    • 我明白了。但是如果一个任务实体确实引用了一个项目成员实体,这是否意味着该成员实体本身就是一个聚合根而不是项目实体的一部分?
    • @user137348 不,不是真的。聚合根之所以这样称呼,是因为它是一个根bit.ly/dERZBI。分支(在这种情况下为成员)不会成为根,因为它下面有另一个分支(任务)。您从聚合根中获得的优势是,您从外部仅与由根表示的整个树“交谈”。每个状态修改都以这种方式通过根绘制所谓的一致性边界。将尝试用我的答案中的代码来反映这一点。
    • 哇,谢谢你提供了很好的代码示例。它不完全是我的域模型,但你对此知之甚少。但无论如何,我现在对聚合根了解得更多,但我也是仍然无法设计我的特定域:-)
    【解决方案2】:

    对于 DDD,请确保在尝试设计域和聚合时不会出现分析瘫痪。它发生在我身上。我的项目实际上已经停止了整整一个月,因为我无法直接获得我的聚合。我说的是一个简单的 3 个数据库表的情况。用户、地址和用户配置文件。

    DDD 的特点是没有像 DONE THE RIGHT WAY 这样的事情。如果您在此处每隔 3 个月发布相同的问题,您将始终得到“专家”在每个问题上为您提供完全不同的答案。 Amis L. 很友好地给了你一个简单的例子。大多数人会从 Eric 的书中复制和粘贴。

    随心所欲。归根结底,无论您的域名如何手工制作,它都永远不适合社区。放松一下,享受编码的乐趣。

    【讨论】:

      猜你喜欢
      • 2010-11-30
      • 2012-06-27
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      • 2014-10-26
      相关资源
      最近更新 更多