Domain driven design DDD-聚合根并创建行为对象

Domain driven design DDD-聚合根并创建行为对象,domain-driven-design,Domain Driven Design,我想就如何避免编写仅仅是数据容器的对象征求一些建议 考虑以下聚合根: public class Post : IAggregateRoot { List<Comment> Comments {get; set;} } 还是这条路对 public class Post : IAggregateRoot { List<Comment> Comments {get; private set;} public void AddComment(stri

我想就如何避免编写仅仅是数据容器的对象征求一些建议

考虑以下聚合根:

public class Post : IAggregateRoot
{
  List<Comment> Comments {get; set;}
}
还是这条路对

public class Post : IAggregateRoot
{
      List<Comment> Comments {get; private set;}
      public void AddComment(string message)
      {
        Comments.Add(new Comment(message)); 
      }
}
这就是Eric Evan所说的聚合根是原子的吗


如果是这种情况,是否意味着实体没有任何公共setter,而是有支持方法(AddThis、RemoveThat)?这就是创建具有丰富行为的对象的方式吗?

聚合根的概念是正确的,但这两个选项实际上都是关于实现的,而且都是有效的

选项1

  • 优点:您的实体接口仍然存在 很干净

  • 缺点:
    Add
    方法需要逻辑 理顺两个部门之间的关系
    Post
    Comment
    (思考 NHibernate)。你可以创建一个 强类型集合和 重写Add方法,或者您可以 将事件发回
    Post
    to 处理

选项2

  • 优点:
    Add/Remove
    方法为布线逻辑提供了方便的位置

  • 缺点:随着集合属性数量的增加,添加/删除方法的数量可能会激增。此外,公开的集合必须是只读的,以确保始终使用特殊方法添加/删除
    注释

我的首选是选项1-我使用引发事件的通用集合。依我看,这感觉更自然,其他开发人员也更容易编写代码。尽管其他人对此表示反对


当我们谈论行为时,我们谈论的是将逻辑附加到实体上。例如,如果您想在5天后停止添加
注释
,您将询问
帖子
添加
注释
是否有效,并且
帖子
将包含进行检查的逻辑。

我会选择第二个选项

首先,我喜欢将集合显示为IEnumerable。这样,就不可能如此轻松地操纵该列表,并且可以防止不必要的行为。我定期检查对象是否包含在列表中的添加和删除方法

其次,它被封装了,然后我可以添加一些逻辑

最后,您可以通过返回方法本身来使用该方法进行方法链接:

var post = new Post()
    .AddComment("My First comment")
    .AddComment("My Second comment")
    .Publish();
如果AddX方法使实体膨胀过多,则可以使用重载:

var post = new Post()
    .Add(new Comment("My First comment"))
    .Add(new Comment("My Second comment"))
    .Publish();

这两种方法都可能是错误的,除非您有充分的理由将
Post
Comments
聚集在一起。您试图用大型集群聚合保护哪些业务不变量?如果没有,则
Comment
应该是它自己的聚合根。
var post = new Post()
    .AddComment("My First comment")
    .AddComment("My Second comment")
    .Publish();
var post = new Post()
    .Add(new Comment("My First comment"))
    .Add(new Comment("My Second comment"))
    .Publish();