Ever since reading Domain Driven Design by Eric Evans, I have been obsessively object modelling every application I write. I am surprised to find that I can hardly ever use aggregation (although I think I should be modelling aggregates). My limited use of aggregates comes from my inability to follow the Aggregation rules, which are,
- Objects whose lifecycle are tied to another object indicate a possible aggregate relationship
- Objects outside of the aggregate cannot hold references to objects inside the aggregate, only the aggregate 'root' is referenceable
- The Aggregate is resposible for ensuring invariants (consistency and integrity) within the aggregation
Domain Driven Design encourages 'Aggregate Boundaries', which means classes outside of the aggregate do not hold references to objects within the boundary. Eric Evans suggests that "Transient references to internal members can be passed out for use within a single operation only." (P. 129), which I imagine means convenience access for one-off operations, but no persisted references.
My aggregate issue tends to crop up whenever I have relationships between objects that validate combinations for proper construction of another object (Does this make any sense?). An example is required to explain here. Take the following diagram,
Imagine an application designed to help people configure and purchase PCs. This application restricts the Processors that can be included in a PC by displaying and allowing the user to only select valid processors for a chosen manufacturer. The system wouldn't allow you to select an "Intel Athlon 50Mhz", because such a chip doesn't exist. Manufacturers produce certain classes of chips which in turn run at certain clock speeds. I believe this is an aggregate relationship since If I delete a manufacturer from the system, all the related chip classes should be removed as they cannot be shared across manufacturers. The model seems to support the requirements.
However, the problem comes when I have an actual instance of a PC with a selected Chip. I want the Chip object to have a specified manufacturer, class and clock speed, which are a valid combination and are references to these objects in the system (I.e. if I change a chip class name it should be applied to every PC that has it selected). Connecting my PC object to a Chip object and a Clock speed violates the aggregate boundaries. See the following "UML" diagram, which demonstrates this violation.
I have now run into this problem on 3 of the real world applications I have Domain Modeled. My suspicion is that my concepts are not quite modelled correctly, or that perhaps my aggregate is not really an aggregate. In any case, I have left the relationships as simple associations which I feel doesn't completely express the domain.