I'm in the beginning stages of trying to apply DDD to a project that I'm working on that has an extremely anemic domain model. Right now I'm trying to currently figure out the best way to offload complex business logic to domain services, while keeping behavior explicitly modeled on my entity at the same time.--For example, let's say I'm working with the standard Order aggregate and I want to encapsulate the behavior of calculating taxes for the order. My first pass at the interface might look like.
class Order {
Taxes CalculateTaxes() {}
}As an aside, I'm requiring the client to call CalculateTaxes() explicitly whenever an updated tax amount is needed, rather than storing taxes directly in the order itself. This is to avoid the overhead of having to maintain an invariant like "Tax Amount will be the sum of order item totals * effective tax rate". I don't to have to calculate taxes every time I modify something on the order, and I definitely don't want to be in a situation where the tax amount is stale or incorrect. I only point this out in case there's something fundamentally wrong with my approach, which could be causing my confusion in the first place.Calculating taxes in my domain can get fairly complex and also requires remote service calls. That's definitely not something I would like to put right in my entity, so I'll create a domain service to handle it called IOrderTaxCalculationService:
interface OrderTaxCalculationService {
Taxes CalculateTaxes(Order order);
}So far that seems pretty straightforward to me, but now I get confused as to the best way to use this fancy new service and keep behavior on my entity at the same time. From what I've read, general wisdom seems to discourage me from injecting this service into the constructor of my entity, and instead favor passing the service in as an argument to my entity method
class Order {
Taxes CalculateTaxes(IOrderTaxCalculationService service) {
return service.CalculateTaxes(this);
}
}However, I don't really see the benefit to this. Assuming I'm using an IoC container, injecting the dependency in the constructor rather than the method wouldn't cause anymore coupling right? It also just forces any consumer of the Order aggregate to inject this dependency themselves, which seems to be an extra maintenance burden. For the sake of argument, assume I don't need to swap out different implementations of the tax calculator at runtime.What don't I understand about the method injection approach that would make it better than constructor injection in the general case?Thanks,Mike
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
AddItem(item, taxService, discountService) // Or any other concept the business will come up with
RemoveItem(item, taxService, discountService) cart.AddItem(item);
discountService.ApplyDiscounts(cart);
taxService.CalculateTaxes(cart);class Order {
Taxes CalculateTaxes(IOrderTaxCalculationService service) {
return service.CalculateTaxes(this);
}
}
That code fragment seems to imply that the service can query the Order. I don't expect aggregates to support queries, I expect them to pass their current state (the relevant parts of it) to the domain services. So, guessing that tax calculation is based on the aggregate collection of items, I'd expect a signature like
class Order {
Taxes CalculateTaxes(IOrderTaxCalculationService service) {
return service.CalculateTaxes(this.items);
}
}
Second thought; when I see this
AddItem(item, taxService, discountService)
cart.AddItem(item);
discountService.ApplyDiscounts(cart);
taxService.CalculateTaxes(cart);