views:

231

answers:

3

I want to write a factory method to instantiate an entity that is an aggregate root.

Should the method accept the aggregated child entities and values as instantiated objects, or should it accept only primitive types?

For example, if I had an entity Computer composed of a Processor and a Memory object, should the factory method take the form:

public Computer NewComputer(
    string computerName, 
    int processorCores, 
    int processorClockSpeed, 
    string memoryType, 
    int memoryRam) 
{
    ...
}

or

public Computer NewComputer(
    string computerName, 
    Processor processor, 
    Memory memory) 
{
    ...
}

Is it only a matter of taste, or are there any serious considerations here?

+1  A: 

It's just a matter of taste, though it can depend on your object-creation strategy, plus you might mix and match them.

Where your aggregate root already has factory methods for its child objects (e.g., if CreateProcessor() already exists to support adding additional processors), your first approach might be appropriate.

Alternately, if you're using a ComputerFactory (or repository) to create or reconstitute your aggregate root, that factory may already knows how to create child objects, in which case it will create them en route to building up your aggregate's graph and your second approach will be appropriate.

Jeff Sternal
+1  A: 

An 'aggregate root' is the topmost node of an object graph. All other objects are created and accessed via this root object. In other words: If you create the components of the Computer class by an external factory method, then you cannot call it 'aggregate root' any more. This is not to say that your second example is somehow bad or smelly or something, it's just that it doesn't meet the 'aggregate root' concept...

Thomas Weller
Would it make any difference if Processor and Memory were value objects?
sandy
Yes, indeed. If Computer is an entity (be it an aggregate root or not), and Processor and Memory were value objects, then the Computer instance _must_ create them internally. 'Injecting' them would be totally senseless, since this would be nothing than a stupid copy-operation.
Thomas Weller
It would be more than a stupid copy operation: it would be encapsulating the responsibility for creating the objects somewhere else (in a factory or repository, for example). If you have a `PurchaseOrder` aggregate root that contains a collection of `LineItem` entities (among other things), what would `PurchaseOrder`'s constructor look like?
Jeff Sternal
PurchaseOrder will have a factory method to create a LineItem, or otherwise PurchaseOrder cannot be called an 'aggregate root'. And btw.: We're talking about value objects, not entities...
Thomas Weller
@Thomas - I still don't understand what PurchaseOrder's constructor should look like given your restrictions. By my read of the DDD book (and according to the samples on the dd web site) it's perfectly legitimate to encapsulate entity and value object creation in a factory class external to an aggregate root that contains those entities/value objects (though that's just one strategy of many - a factory method on the aggregate root works too, for some cases).
Jeff Sternal
@Jeff - it's of course a valid strategy to have a Factory for an enity whenever it is appropriate. My point was, that a) the initial question was about value objects, not entities, and you should never have factories for VAs b) an OrderLine does not make sense outside the context of a PurchaseOrder, therefore IMHO the PurchaseOrder class should be the point of creation for an OrderLine - something like 'PurchaseOrder.AddLine(orderData)' - and the c'tor should be irrelevant in that respect.
Thomas Weller
I never buy the idea of aggregate being responsible for subentities creation. E.g. in my current project, I have 10 different kinds (subclasses) of OrderLines... should I have 10 AddOrderLineXXX methods on my Order? I don't think that Order should always care about items creation, nor I think that computer should be responsible for processor creation... unless it's truly alive (AI) ;-)
queen3
+1  A: 

Regarding to the benefits of using the Factory Method (I am not very familiar with the rules of Aggregates and Roots):

  • I imagine Processor and Memory are objects having certain behaviors that you want to separate from your Computer Class.
  • The computer class constructor could be

    public Computer(string computerName, IProcessor processor, IMemory memory) { }

Your Computer class now does not depend on specific implementation of Processor and Memory. Other class is responsible on using a computer with specific Memory and Processor.

With this approach you will have benefits of having more maintainable code, and being able to upgrade the Memory and Processor without changing the Computer.

Dont know if this answear your question in your particular scenario, but Hope this helps. Other resources are:

  1. http://www.objectmentor.com/resources/articles/inheritanceVsDelegation.pdf
  2. SOLID ebook: http://www.lostechies.com/content/pablo%5Febook.aspx