views:

163

answers:

2

I want to ask for some advise on how to avoid writing objects which are mere data containers.

Consider the following Aggregate Root:

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

Given the pinciples that govern how aggregate roots work, is it valid to call the above code like this?

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

Or is this the right way?

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

And called like this:

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

Is this what Eric Evan means by Aggregate Roots being atomic?

If this is the case, does it mean that Entities do not have any public setters, but instead have supporting Methods (AddThis, RemoveThat)? Is this how you create objects with rich behaviour?

+3  A: 

You've got the concept of aggregate roots correct, but your two options are really about implementation - and both are valid.

Option 1

  • Pros : Your entity interface remains quite clean.

  • Cons : The Add method needs logic to wire up the relationship between the Post and the Comment (think NHibernate). You could create a strongly typed collection and override the Add method, or you could raise events back to the Post to handle.

Option 2

  • Pros : The Add/Remove methods provide a convenient place for the wiring logic.

  • Cons : As the number of collection properties grows, you might have an explosion of Add/Remove methods. Also, exposed collections must be ReadOnly, to ensure that Comments are always added/removed using the special methods.

My preference is Option 1 - I use generic collections that raise events. IMHO, it feels more natural, and is easier for other developers to code against. Although others on SO have expressed otherwise.

When we talk about behaviour, we're talking about attaching logic to the Entity. Eg. if you wanted to stop Comments being added after 5 days, you would ask the Post if adding a Comment is valid, and the Post would contain the logic to do the check.

Vijay Patel
+2  A: 

I'd go with second option.

Firstly I like to show collections as IEnumerable. That way it's not possible to manipulate that list so easily and it's protected against unwanted behavior. Regularly I check in adding and removing method that if object contains in list or not.

Secondly it encapsulated and I can add some logic afterwards.

Finally you can make method chaining with that method by returning back itself:

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

If AddX method is to much bloating your entity, then it possible to do it with overloading:

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