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 的概念放在同一个限界上下文中。这似乎是合乎逻辑的或至少是隐含的,当您在创建订单的过程中时,您会想知道应缴税款,但这是否一定适用于您的域?
顺便说一句,我并不是说它可以或不可以——我只是说针对您的特定领域考虑一下。很多时候,当模型看起来很难表示时,是因为它混合了不属于一起的问题。
假设经典 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 的概念放在同一个限界上下文中。这似乎是合乎逻辑的或至少是隐含的,当您在创建订单的过程中时,您会想知道应缴税款,但这是否一定适用于您的域?
顺便说一句,我并不是说它可以或不可以——我只是说针对您的特定领域考虑一下。很多时候,当模型看起来很难表示时,是因为它混合了不属于一起的问题。