DDD: How do structure or resolve more complex behaviour in a domain entity?

自闭症网瘾萝莉.ら 提交于 2021-02-08 07:22:16

问题


Assume the classic Order/OrderLine scenario.

public class Order {
 ...
    public void AddOrderLine(OrderLine ol) {
        this.OrderLines.Add(ol);
        UpdateTaxes();
    }


    private void UpdateTaxes() {
        //Traverse the order lines
        //Collect the VAT amounts etc
        //Update totals 
        var newTaxes = Orderlines.SelectMany(ol => ol.GetTaxes());
        Taxes.Clear();
        Taxes.Add(newTaxes);

    }

}

Now, we figure that we need to handle taxes better, with different ways for customers in various countries etc, where some require VAT to be collected and others not.

In short, the tax rules will depend on the customer's location, items purchased etc. How would we do this? Should we put a lot of code into UpdateTaxes? Could we use tax calculator factory and reference it in UpdateTaxes?

private void UpdateTaxes() {
    var taxRules = TaxRulesFactory.Get(this);
    var taxes = taxRuleCalc.Apply(this);
    Taxes.Clear();
    Taxes.Add(taxes);
}

回答1:


Considering your broader question regarding complex behaviour in ARs the preferred way to handle this would be to use double-dispatch. Bear in mind that complex behaviour certainly can be included in the AR if that behaviour is cohesive.

However, for functionality that varies to the degree of tax or even discount calculation, where one would implement various strategies, you could opt for the double dispatch:

public class Order
{
    public void ApplyTax(ITaxService taxService)
    {
        _totalTax = taxService.Calculate(TotalCost());
    }

    public void ApplyDiscount(IDiscountService discountService)
    {
        _discount = discountService.GetDiscount(_orderLines.Count, TotalCost());
    }

    public Money TotalCost()
    {
        // return sum of Cost() of order lines
    } 
}

These services also should not be injected into the AR but rather passed into the relevant method.




回答2:


May be you could extract UpdateTaxes into a separate class which would be responsible for tax calculation against a particular order. And itself would chose an appropriate strategy (a separate strategy class) depending on customer, order, etc. I feel that tax calculation is a separate responsibility here.




回答3:


You might also have a think about whether the concept of Tax and the concept of Orders need to be located within the same bounded context. It perhaps seems logical or at least implicit that when you're in the process of creating an Order you will want to know Tax due, but does this necessarily apply in your domain?

I'm not saying it does or it doesn't, by the way -- I'm simply saying think about it for your particular domain. Very often when the model seems awkward to represent it's because it mixes concerns that don't belong together.



来源:https://stackoverflow.com/questions/33069570/ddd-how-do-structure-or-resolve-more-complex-behaviour-in-a-domain-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!