DDD - 聚合根和创建行为对象

时间:2009-10-19 06:04:10

标签: domain-driven-design

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

考虑以下聚合根:

public class Post : IAggregateRoot
{
  List<Comment> Comments {get; set;}
}

鉴于管理聚合根的工作原理,是否可以像这样调用上面的代码?

new Post().Comments.Add(New Comment("stuff"));

或者这是正确的方法吗?

public class Post : IAggregateRoot
{
      List<Comment> Comments {get; private set;}
      public void AddComment(string message)
      {
        Comments.Add(new Comment(message)); 
      }
}

并且这样称呼:

new Post().AddComment("stuff");

这是Eric Evan意味着Aggregate Roots是原子的吗?

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

2 个答案:

答案 0 :(得分:5)

你已经有了聚合根的概念,但你的两个选择实际上是关于实现 - 两者都是有效的。

选项1

  • 优点:您的实体界面仍然存在 很干净。

  • 缺点:Add方法需要逻辑 连线之间的关系 PostComment(想想 NHibernate的)。你可以创建一个 强类型集合和 覆盖Add方法,或者你可以 将事件提升回Post 处理

选项2

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

  • 缺点:随着集合属性数量的增加,您可能会遇到Add/Remove个方法。此外,公开的集合必须是ReadOnly,以确保始终使用特殊方法添加/删除Comments

我的偏好是选项1 - 我使用引发事件的泛型集合。恕我直言,感觉更自然,其他开发人员更容易编码。虽然SO上的其他人表示不同意。

当我们谈论行为时,我们谈论的是将逻辑附加到实体。例如。如果您想在5天后停止Comments添加,则会询问Post添加Comment是否有效,而Post将包含执行此操作的逻辑检查。

答案 1 :(得分:3)

我会选择第二种选择。

首先,我喜欢将集合显示为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();