验证数据合法是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);