Reputation: 179
I'm developing app using DDD pattern.
I have Invoice
class in domain layer.
public class Invoice
{
List<InvoiceLine> list = new List<InvoiceLine>();
public DateTime Date { get; set; }
public Customer Customer { get; set; }
public decimal GrandTotal
{
get
{
// Simplified grand total.
// It's actually include tax and discount to calculate.
decimal total = 0m;
foreach(InvoiceLine line in Lines)
total += line.LineTotal;
return total;
}
}
public IEnumerable<InvoiceLine> Lines
{
get { return list; }
}
public void AddLine(InvoiceLine line)
{
lines.Add(line);
}
}
I'm using mvvm pattern so i also have a viewmodel to edit invoice. My question is where should i put the business logic to calculate GrandTotal so that the business logic on domain and presentation is the same ?
Should i just duplicate the code from domain to presentation (Invoice
to InvoiceViewModel
)? or make a service that both domain and presentation could use?
Upvotes: 2
Views: 1138
Reputation: 1319
The main goal of aggregates in DDD is to maintain consistency - in your case consistency means for example that GrandTotal will always have correct value. That said, there's no rule that states that aggregate class cannot use additional classes to obtain this consistency.
For example, you could provide a class which sole responsibility is to calculate grand total and use it in your domain and view model. I wouldn't call it service as it has nothing to do with DDD concepts. Example:
public interface IInvoiceLine
{
decimal Amount {get;}
}
public interface ICalculateGrandTotal
{
decimal Calculate(IEnumerable<IInvoiceLine> lines);
}
public class GrandTotalCalculator: ICalculateGrandTotal
{
...
}
Now you can use this calculator in both view model and domain without code duplication. In addition due to interfaces, there's no direct coupling between view model and domain classes. IInvoiceLine
interface can be separately implemented by view model and domain entities.
Upvotes: 2