因为我用的是 OVal,所以我可以完成下列任务:
对 fileSet 类成员指定一个约束条件,确保使用 @Size 标注时其大小总是至少为 1 或更大。
确保在使用 @PreValidateThis 标注调用 execute() 方法前 验证这个约束条件。
这两步让我能够有效地去除 validate() 方法中的条件检验,让 OVal 为我完成这些,如清单 11 所示:
清单 11. 经过改进、无条件检验的 HierarchyBuilderTask
@Guarded
public class HierarchyBuilderTask extends Task {
private Report report;
@Size(min = 1)
private List fileSet;
private void validate() throws BuildException {
if (this.report == null) {
this.log("no report defined, printing XML to System.out");
}
}
@PreValidateThis
public void execute() throws BuildException {
validate();
String[] classes = this.getQualifiedClassNames(this.fileSet);
Hierarchy[] hclz = new Hierarchy[classes.length];
try{
for(int x = 0; x < classes.length; x++){
hclz[x] = HierarchyBuilder.buildHierarchy(classes[x]);
}
BatchHierarchyXMLReport xmler = new BatchHierarchyXMLReport(new Date(), hclz);
this.handleReportCreation(xmler);
}catch(ClassNotFoundException e){
throw new BuildException("Unable to load class check classpath! " + e.getMessage());
}
}
//more methods below....
}
清单 11 中的 execute() 一经调用(由 Ant 完成),OVal 会验证 fileSet 成员。如果其为空,意味着没有指定任何要评估的类,会抛出一个 ConstraintsViolatedException。这个异常会暂停这一过程,像初始代码一样,只不过初始代码会抛出一个 BuildException。
结束语
防御性编程结构阻止了一个又一个缺陷,但这些结构本身却不免为代码添加了重复的逻辑。把防御性编程技术和面向方面编程(通过契约式设计)联系起来是抵御所有重复性代码的一道坚强防线。
OVal 并不是惟一可用的 DBC 库,事实上其 DBC 结构对比其他框架来说是相当有限的(例如,它未提供指定类不变式的简易方法)。从另一方面讲,OVal 很容易使用,对约束条件也有很大的选择余地,若想要花少量力气可向代码添加验证约束条件,它无疑是个上佳之选。另外,用 OVal 创建定制约束条件也相当简单,所以请不要再添加条件检验了,尽情享用 AOP 吧!