DDD - a collection of roots and the creation of behavioral objects

I want to ask for advice on how to avoid writing objects that are just data containers.

Consider the following summary root:

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

Given the pinciples that determine how common roots work, is it right to invoke the above code as follows?

 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 that what Eric Evan means Aggregate Roots are atomic?

If so, does this mean that entities do not have public setters, but instead have supporting methods (AddThis, RemoveThat)? This is how you create rich behavior objects?

+7
design domain-driven-design
source share
2 answers

You have the correct concept of aggregate roots, but your two options are really implementation related - and both are valid.

Option 1

  • Pros: Your entity’s interface remains pretty clean.

  • Cons: The Add method requires logic to link the relationship between Post and Comment (think NHibernate). You can create a strongly typed collection and override the Add method, or you can return events back to Post before the handle.

Option 2

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

  • Cons: As the number of collection properties increases, you may have an explosion of Add/Remove methods. In addition, open collections must be ReadOnly to ensure that Comments always added / removed using special methods.

My preference is option 1 - I use shared collections that trigger events. IMHO, it feels more natural, and other developers find it easier to program. While others on SO expressed differently.

When we talk about behavior , we are talking about binding logic to Entity. For example. if you want to stop Comments being added after 5 days, you must set Post if Comment is added and Post will contain the logic to check.

+5
source share

I would go with the second option.

First, I like to show collections as IEnumerable. Thus, it is not possible to easily manipulate this list and protect it from unwanted behavior. I regularly check the method of adding and deleting, which if the object is listed or not.

Secondly, it is encapsulated, and I can add some logic afterwards.

Finally, you can chain the methods using this method by returning yourself:

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

If the AddX method greatly inflates your object, then this can be done with overloading:

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

All Articles