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

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

假设经典 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);
}

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

考虑到您关于 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 中,而是传递到相关方法中。

您可能还会考虑是否需要将 Tax 的概念和 Orders 的概念放在同一个限界上下文中。这似乎是合乎逻辑的或至少是隐含的,当您在创建订单的过程中时,您会想知道应缴税款,但这是否一定适用于您的域?

顺便说一句,我并不是说它可以或不可以——我只是说针对您的特定领域考虑一下。很多时候,当模型看起来很难表示时,是因为它混合了不属于一起的问题。