DDD - Modifications of child objects within aggregate
The domain event is the most robust solution.
However if that's overkill you can also do a variation of #2 using the Parameter Object pattern - have a single ModfiyOrderItem function on the entity root. Submit a new, updated order item, and then internally the Order validates this new object and makes the updates.
So your typical workflow would turn into something like
var orderItemToModify = order.GetOrderItem(id);
orderItemToModify.Quantity = newQuant;
var result = order.ModifyOrderItem(orderItemToModfiy);
if(result == SUCCESS)
{
//good
}
else
{
var reason = result.Message; etc
}
The main shortcoming here is it allows a programmer to modify the item, but not commit it and not realize that. However it is easily extensible and testable.
One drawback of 4 as opposed to 2 is lack of consistency. In certain instances it might be beneficial to maintain a degree of consistency in regards to updating order line items. It may not be immediately clear why certain updates are done through the order while others through the order line item. Furthermore, if order lines have 20+ properties, perhaps that is a sign that there is potential for grouping among those properties resulting in fewer properties on the order line. Overall, approach 2 or 4 is fine as long as you make sure to keep operations atomic, consistent and in correspondence with ubiquitous language.
Is not optimal because it allows breaking domain invariant.
Will result in code duplication and unnecessary method explosion.
Is the same as 1). Using Value Object will not help with maintaining domain invariant.
This option is what I would go with. I would also not worry about potential and hypothetical changes until they materialize. The design will evolve with your understanding of the domain and can always be refactor later. There is really no value in hindering your existing design for the sake of some future changes that may not happen.
There is a fifth way of doing this. You can fire a domain event (e.g. QuantityUpdatedEvent(order, product, amount)
). Let the aggregate handle it internally by going through the list of orderlines, select the one with matching product and update its quantity (or delegate the operation to OrderLine
which is even better)