views:

102

answers:

2

Doing a bit of reading around domain driven design and it seems that you're supposed to access all entities within an aggregate by traversal from the aggregate root.

However, at the same time you should really try and encapsulate your data so that the properties/fields are protected or private.

Therefore my question is: If the fields are protected/private how are you supposed to traverse the aggregate?

The way I have set it up at the moment is as follows: I mark all the properties of my domain model as internal with the methods for "setting" marked as protected. This way, at least nothing outside the model can access the properties, but objects within the model can access other objects properties and I still only allow setting of the properties from within the object itself.

Even though I've done this, I still feel as if this should only apply for properties for other aggregate entities (I mean, a Customer's "name" would still be private, but their "Orders" should be marked as internal to allow for the traversal from Customer -> Orders -> etc.)

Does anyone have any guidance on this?

EDIT:

Let me try and give a more concrete example for the question: I have a two objects in my object graph: Bookshelf and Book. Let us say for the sake of this example that Bookshelf is the aggregate root, and that Books are stored on a bookshelf so are just entities within the aggregate (Bookshelf has a collection of books).

I want to write a method to add a new book to the bookshelf. Following DDD best practices, I believe I should write a method on the Bookshelf class such as AddBook(Book book).

However, what if there is a business requirement that no book with the same title can be added to the bookshelf. I want some logic within the Bookshelf.AddBook method to check the collection of books to make sure this book doesn't already exist.

The problem now is that I can't do that as I've written the Book object in a nicely encapsulated way and its "Name" property is not publicly accessible.

I understand this is a fairly contrived example, but I hope that it better illustrates the problem. I also now realise that this isn't just a DDD problem, but an OO encapsulation one in reality. I'm sure that there must be a very common, easy way of solving what I'm trying to do and I'm massively overthinking it.

A: 

The Visitor pattern is the typical traversal mechanism.

David Gladfelter
That's not quite the type of traversal I think is meant here. The visitor pattern would let me traverse the object graph and perform an action upon each node of the graph. However, I'm talking about just referencing contained objects from the parent entity - for example: var customerOrderLineItems = customer.Orders[0].OrderLines;
Justin
You have a couple of choices. First of all, some believe that you shouldn't "reach into" objects like that. That's an indication that you're treating the object graph as dumb-value holders rather than as self-contained, self-managed entities. If an operation is integral enough to a class, it should be an operation on the class, delegating to private contained objects as needed. If you need a decoupled system with double-dispatch, then the visitor pattern is the way to go. Any other approach ties multiple methods to multiple objects in an N * M set of relationships: a maintenance problem.
David Gladfelter
+1  A: 

There is nothing wrong in exposing properties in case of storng, composition-like relation between parent and its children. Child properties are exposed to the parent, but because their strong relationship and interdependenace it doean't break encapsulation.

In other words, there is nothing wrong in exposing Book's name property to the Bookshelf, but it would be wrong (in sense of DDD best practices) to expose Book's name to other aggregates. It would be also wrong to expose modifiable collection of books. Exposing read-only collection should be done with caution -- it can be sign of breaking of encapsulation.

Does this answer your question?

Szymon Pobiega
It does answer the question, and I suppose that's what I meant by saying I was overthinking it - it's as easy as just relaxing the rules slightly and making the property available, but only within the aggregate.The question that arises is what C# language features would you use to allow access to the Name of the book to the bookshelf, but not to classes outside that aggregate? (Thinking about it in terms of the different aggregates for one bounded context being within one c# assembly)
Justin