Reputation: 9939
I have an aggregate root Order
with corresponding OrderService
and OrderRepository
.
I have an ExtendedOrder
with corresponding ExtendedOrderService
and ExtendedOrderRepository
.
For example:
class Order {
int GetOrderId();
}
class ExtendedOrder : Order {
string GetExtendedInfo();
}
I would like to have OrderService
to return both type Order
and ExtendedOrder
as a list of Order
. But to obtain ExtendedOrder
it should ask to the corresponding ExtendedOrderService
when the Order
is of type ExtendedOrder
.
Is it possible to obtain this behavior? Is it legal to have an aggregate root extend another aggregate root?
Upvotes: 5
Views: 3012
Reputation: 13457
Given that ExtendedOrder inherits from Order then you would not normally have an ExtendedOrderRepository and ExtendedOrderService - the OrderRepository and OrderService would be sufficient.
An ExtendedOrder is still an Order, so it should live within the boundaries of the Order aggregate root and use the OrderRepository and OrderService.
The OrderRepository will return Order objects, which may or may not be Extended Orders. ORMs such as NHibernate support this behaviour out of the box.
Working in this way lends itself to more elegant code and less repetition. Code might look like:
public class Order
{
public virtual void Process()
{
// do processing stuff to an order
// ...
}
}
public class ExtendedOrder : Order
{
public override void Process()
{
// do the standard order processing
base.Process();
// do extra processing specific to an extended order
// ...
}
}
public class OrderService
{
public void ProcessRecentOrders()
{
IEnumerable<Order> orders = orderRepository.GetRecentOrders();
// orders may include Order and ExtendedOrder objects in the collection...
foreach (Order in orders)
{
// ...but polymorphism ensures that we don't need to know whether order is an ExtendedOrder or an Order
order.Process();
}
}
}
and if need be you can still explicitly distinguish between Order and ExtendedOrder:
public void SendOrder(Order order)
{
// do normal order sending stuff
orderSender.TransmitOrder(order);
if (order is ExtendedOrder)
{
// do additional stuff required by an ExtendedOrder
}
}
This approach lets you continue to create other Order types (e.g. "SpecialOrder") without a proliferation of repositories and services.
Upvotes: 2
Reputation: 14064
If the Extended
part of ExtendedOrder
is really a domain concept and part of the ubiquitous language (as opposed to a purely UI commodity) I'd favor composition over inheritance and make it a separate entity, ExtendedOrderDetails
for instance.
It would be part of the Order aggregate and thus accessible through the Order
provided by OrderService
.
Upvotes: 2
Reputation: 1319
The main question is, what do you need it for. I suspect it's related with some kind of UI or reporting functionality. If that's the case my advise would be to not use Domain Model concepts for these queries.
In other words separate Domain Model concepts, which are great for keeping consistency and achieving control over complex business logic, from reporting-related queries (presenting results on UI is a form of report after all). Failing to do that separation at some point always leads to adjusting Domain Model in order to fulfill the requirements of some kind of UI or report, and this shouldn't happen.
In your case I'd simply prepare a query that ignores the aggregate and selects all the data that I need. Of course, when some business action is to be performed on the results it should use Domain Model. After all aggregates are responsible for keeping the consistency, and the only thing that will have a chance to mess with consistency is updating the data - reading the data will not cause changes, thus using aggregates for reads is kinda pointless in my opinion.
To sum up - reporting-related functionality in most scenarios shouldn't cause adjustment in Domain Model business concepts.
Upvotes: 5
Reputation: 4433
You don't need an ExtendedOrderService. Just use one OrderService to coordinate results from OrderRepository and ExtendedOrderRepository.
See the answer to this question for more on the role of Application Services. An Application Service can utilize multiple repositories.
Upvotes: 6