我正在尝试处理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; }
...
}
应该使用其他一些构造来表示较弱的关系类型吗?
答案 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);