I am trying to get my hands dirty learning DDD (by developing a sample eCommerce site with entities like Order
, OrderLines
, Product
, Categories
etc).
From what I could perceive about Aggregate Root concept I thought Order
class should be an aggregate root for OrderLine
.
Things went fine so far, however I am confused when it define a create order flow from UI.
When I want to add an order line to my order object, how should I get/create an instance of an OrderLine
object:
- Should I hardcode the new
OrderLine()
statement in my UI/Service class
- Should I define a method with parameters like
productID
, quantity
etc in Order
class?
Also, what if I want to remove the hardcoded instantiations from the UI or the Order
class using a DI. What would be the best approach for this?
From what I could perceive about
Aggregate Root concept I thought Order
class should be an aggreagrte root for
OrderLine.
Yes, OrderLine's should most likely be under an Order root, since OrderLine's likely make no sense outside of a parent Order.
Should I hardcode the new OrderLine()
statement in my UI/Service class
Probably not, though this is how it happens often and it is made to work. The problem, as I see it, is that object construction often happens in different contexts, and the validation constraints differ depending on that context.
Should I define a method with
parameters like productID,quantity etc
in Order class?
As in:
public OrderLine AddOrderLine(Product product, int Quantity ... )
This is one way to do it. Notice I used a Product class instead of a ProductId. Sometimes one is preferable to the other. I find I use both a lot for various reasons - sometimes I have the ID and there's no good reason to pull the aggregate root, sometimes I need the other root to validate the operation.
Another way I do this is to implement a custom collection for the children.
So I have:
order.OrderLines.Add(product, quantity);
This feels a little more natural or OO, and in particular if an entity root has many child collections it avoids clutter.
order.AddOrderLine()
, order.AddXXX()
, order.AddYYY()
, order.AddZZZ()
versus
order.OrderLines.Add()
, order.ZZZs.Add()
, order.YYYs.Add()
Also, what if I want to remove the
hardcoded instantiations from the UI
or the Order class using a DI. What
would be the best approach for this?
This would be a textbook case for the Factory pattern. I inject such a Factory into my custom collections to support instantiation in those Add()
methods.
You could use an OrderLine Factory to get instances of Orderlines. You would "new up" an OrderLine object in the factory with parameters passed into the factory method and then return the new instance to your Order object. Always try to isolate instantiations and dont do it in the UI. There is a question here that uses this technique.
Here is a great book you will find useful on DDD.