Reputation:
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?
Upvotes: 7
Views: 733
Reputation: 1914
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();
Upvotes: 3
Reputation: 17532
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.
Upvotes: 5