DDD:如何在域实体中构造或解决更复杂的行为?

时间:2015-10-11 20:05:54

标签: domain-driven-design

假设经典的Order / OrderLine场景。

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);

    }

}

现在,我们认为我们需要更好地处理税收,为不同国家的客户提供不同的方式等,其中一些需要征收增值税,而另一些则不需要。

简而言之,税收规则将取决于客户的位置,购买的商品等。我们如何做到这一点?我们应该将大量代码放入UpdateTaxes吗?我们可以使用税务计算器工厂并在UpdateTaxes中引用它吗?

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

3 个答案:

答案 0 :(得分:4)

考虑到有关AR中复杂行为的更广泛问题,处理此问题的首选方法是使用双重调度。请记住,如果行为具有凝聚力,那么复杂的行为当然可以 包含在AR中。

但是,对于根据税收甚至折扣计算而变化的功能,如果要实施各种策略,您可以选择双重发送:

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
    } 
}

这些服务也不应该注入AR,而是传递给相关方法。

答案 1 :(得分:2)

可能是您可以将UpdateTaxes提取到一个单独的类中,该类将负责针对特定订单的税收计算。并且它本身会根据客户,订单等选择合适的策略(单独的策略类)。我觉得税收计算在这里是一个单独的责任。

答案 2 :(得分:2)

您可能还需要考虑税务概念和订单概念是否需要位于相同的有界环境中。这似乎是合乎逻辑的,或者至少是隐含的,当您在创建订单的过程中,您将需要了解到期税,但这是否必然适用于您的域?

顺便说一下,我并没有说它确实存在,或者它没有说 - 我只是简单地为你的特定领域考虑它。通常情况下,模型似乎很难代表它,因为它混合了不属于一起的问题。