验证数据合法是DDD中富有争论的额一点,例如,货物达到最大重量的验证方式像这样:
public class Cargo extends AggregateRoot {private int maxWeight;private List<Product> items;public Cargo(int maxWeight) {this.maxWeight = maxWeight;items = newList < Product > ();}public void addItem(Product product) {int currentWeight = items.stream().mapToInt(x -> x.weight).sum();if (currentWeight + product.weight > maxWeight)throw new InvalidStateException();items.add(product);}}
在addItem方法中,如果产品重要超过最大重量将抛出异常且不会加入到list中。另一种方式是
public class Cargo extends AggregateRoot {public int maxWeight;private List<Product> Items;public Cargo(int maxWeight) {maxWeight = maxWeight;items = newList < Product > ();}public void addItem(Product product) {items.add(product);}public boolean isValid() {int currentWeight = items.stream().mapToInt(x -> x.weight).sum();return currentWeight <= MaxWeight;}}
这种方式允许任意重量的产品添加至列表。通过调用新增的isValid方法验证。这两种方式各有优劣:
- 每步验证:直观
- 最后验证:所有验证都位于同一位置
每步验证的前提下,程序员很清楚验证细节;最后验证可以将验证代码聚合。如何选择?我的建议是使用每步验证:
- 消除时间耦合
- 遵循DRY原则
原因有二,第一,最后验证这种方式需要在持久化前调用,且有时容易忘记;第二,每步验证遵循DRY原则,消除了代码重复。
- 验证必须处于领域层
像这种在应用服务层的验证是不建议的。我们例子中的所有验证都是处在领域模型中的。String err = snackMachine.canBuySnack(position);if(err != string.isEmpty()){showError(error);return;}snackMachine.BuySnack(position);
