如何在DDD实体中表示引用

时间:2011-06-16 09:36:42

标签: c# domain-driven-design

我正在尝试处理DDD,并且觉得我对实体,聚合,聚合根,存储库和值对象以及如何在代码中实际表示这些概念有很好的把握。

我还在努力解决的是如何在实际代码中表示引用(即不构成聚合的关系)。假设我有以下两个聚合

DISCUSSIONGROUP (entity, aggregate root)
 +name: string
 +ENTRY (entity)
   +title: string
   +message: string
   +timestamp: date
   +madeByUser: USER

USER (entity, aggregate root)
 +name: string
 +email: string
 +memberOf: DISCUSSIONGROUP

用户可以是讨论组的成员,但用户实体不属于同一聚合。然而,两者之间仍然存在关联(参考)。在查看实际代码时,我会实现聚合关系,例如(使用C#):

interface IDiscussionGroup {
    string Name { get; }
    IList<IEntry> { get; }
    ...
}

即使用简单的C#引用。你会以同样的方式实现DDD引用(如上所述),即:

interface IUser {
    IDiscussionGroup MemberOf { get; }
    ...
}

应该使用其他一些构造来表示较弱的关系类型吗?

2 个答案:

答案 0 :(得分:1)

真的取决于你的要求。没有一种方法可以做得很好,但我要做的是将DISCUSSIONGROUP实体中的madeByUser属性设置为ValueObject。

为什么?因为当从DisscusionGroup显示条目时,我对用户的名称和电子邮件非常感兴趣,以便在条目上显示。当我从数据库中删除用户时,我不希望该用户在我的条目中消失。如果用户实体具有更多属性和行为,那么在显示用户信息时我对此不感兴趣,因此ValueObject就可以了。此外,您可以在多个条目之间共享该VO,而无需为每个条目重新获取具体用户的实例。

另一方面,用户聚合在与DiscussionGroup相同的上下文中使用?我的意思是,DiscussionGroup可以是一个上下文中的实体(例如在前台用例中)和用户管理后台中的值对象(我们对管理讨论组没有兴趣,只对用户有兴趣,所以很简单关于disscussiongroup的信息就足够了)。但是,您可能希望从DisscussionGroup实体引用User实体,或者在这种情况下也将DiscussionGroup作为VO。您是否需要检索给定用户的所有discussionGroups和条目?或者您只需要一些可以嵌入到值对象中的信息?

我很抱歉,如果我没有很好地回答你的问题,但直接引用或仅在聚合之间使用某种共享ID或使用VO实际上取决于用例和行为你必须实施。

Personnaly如果我可以在不进行延迟加载和其他类似这样的stuf的情况下检索聚合中的所有数据,我会检查是否定义了良好的聚合边界。

也许其他人有另一种观点。

答案 1 :(得分:0)

“持有某种东西”和“属于某种东西”看起来很相似。

区别在于 - 什么时候构建。

public class User{
  public IList<DiscussionGroup> GroupMembership{get; private set;}
  public User(){
    GroupMembership=new List<DiscussionGroup>();
  }
  public void JoinGroup(DiscussionGroup group){
    GroupMembership.Add(group);
  }
  public bool IsMemberOf(DiscussionGroup group){
    return GroupMembership.Contains(group);
  }
  public void EnsureMembership(DiscussionGroup group){
    ThrowIf(!IsMemberOf(this),
      "User is not a member of this discussion group");
  }
}
public class DiscussionGroup{
  public IList<Discussion> Discussions {get;private set;}
  public DiscussionGroup(){
    Discussions=new List<Discussion>();
  }
  public Discussion CreateDiscussion(string name, Post firstPost){
    CurrentUser.EnsureMembership(this);
    var discussion=new Discussion(this, name, firstPost);
    Discussions.Add(discussion);
    return discussion;
  }
}
public class Discussion{
  public DiscussionGroup Group{get; private set;}
  public Discussion(DiscussionGroup group, string name, Post firstPost){
    CurrentUser.EnsureMembership(group);
    Guard.Null(group);
    Group=group;
    Name=name;
    Posts=new List<Post>{firstPost};
  }
  public void WritePost(string text){
    CurrentUser.EnsureMembership(group);
    Posts.Add(new Post(this,text));
  }
}
public class Post{
  public Discussion Discussion{get; private set;}
  public string Text {get; private set;}
  public Post(Discussion discussion, string text){
    Guard.Null(discussion);
    Discussion=discussion;
    Text=text;
  }
}

//usage
var me=new User();
var you=new User();
var stackOverflow=new DiscussionGroup();
me.JoinGroup(stackOverflow);
you.JoinGroup(stackOverflow);

LoginAs(you);
var question="I'm trying to get a handle on DDD and feel that...";
var discussion=stackOverflow.CreateDiscussion
  ("How to represent references in DDD entites",question);

LoginAs(me);
var answer="'Holds something' and 'belongs to something'...";
discussion.WritePost(answer);