聚合根设计和表示层

时间:2011-01-06 09:26:05

标签: domain-driven-design aggregateroot

我想知道我的表示层是如何构建的,可能会导致设计我的聚合根。

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

页面结构如下:

页面顶部是ProjectEntity的表单

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

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

我想知道这种行为/'页面结构'是否可以作为聚合根的提示(projectentity)

2 个答案:

答案 0 :(得分: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...");
 }
}

请记住,我对您的业务知之甚少。这只是即兴创作。 :)

答案 1 :(得分:0)

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

DDD的东西是没有像DONE THE RIGHT WAY这样的东西。如果你在这里发布相同的问题,彼此间隔3个月,你将始终让“专家”在每个问题中给出完全不同的答案。 Amis L.非常友好地给你一个简单的例子。大多数人都会从埃里克的书中复制和粘贴。

做任何漂浮你的船。在一天结束时,无论您的域名如何手工制作,它都不会对社区产生影响。只是冷静下来,享受编码。