我必须承认,尽管防御性编程有很多好处,但我通常会限制自己不要将可变属性暴露给外界。 这是为什么? 我认为这主要是由于可读性。 看一下下面的代码:
publicList<Person>getPersons(){
returnCollections.unmodifiableList(persons);
}
足够容易阅读和理解。 现在,考虑按合同设计的方法,在这里我要强制执行先决条件, 即运行代码必须满足的条件。
publicvoidsendEmail(Stringemail){
Assert.assertNotNull(email);
// Real code after that
...
}
并不难。 但是现在,我想对电子邮件进行表面检查,以免查询JNDI树中的SMTP服务器。
publicvoidsendEmail(Stringemail){
Assert.assertNotNull(email);
Validatorvalidator=newEmailValidator(email);
validator.validate(email);
// Real code after that
...
}
到目前为止,阅读起来实在太难了。 如果我有多个参数,并且对每个参数进行多次检查,那么复杂性将很快变得不合时宜,而这仅是前提条件! 后置条件检查将在方法结束时进行,甚至会影响可读性。 此外,外界对此一无所知:它们必须用Javadoc手动编写并与代码保持同步。
如果可以取消这些限制怎么办? 我会更倾向于按合同使用设计吗? 我确实认为是这种情况。 当我在法国Devoxx参加Emmanuel Bernard的演讲时,我简直不敢相信用法会如此简单。 我的目标只能通过使用Bean Validation API 1.1 (又名JSR-349 )来实现。 这个较新的版本重用了Bean Validation 1.0(又名JSR-303 )注释,但是在以前的版本中,仅可以对属性进行注释,而现在方法也可以。 或者更笼统地说,在状态验证之前,现在我们可以按合同进行设计。
以前的方法可以这样更新:
publicvoidsendEmail(@EmailStringemail){
// Real code after that
...
}
Kill-joys可能会反对它很好,但它仍处于起草阶段。 没错,除了HTML5作用域之外。 此外,Hibernate Validator是Bean Validation API 1.0参考实现。 很自然,对于Hibernate Validator 5,1.1版也是如此。但是,它已经提供了4.2版所需的一切。 如果您愿意使用Spring,这很容易:
- 在您的POM中获得正确的依赖关系
<dependency> <groupId> org.springframework </groupId> <artifactId> spring-context </artifactId> <version> 2.3.2 </version> </dependency> <dependency> <groupId> org.hibernate </groupId> <artifactId> hibernate-validator </artifactId> <version> 4.3.1.Final </version> </dependency>
- 如上所述注释您的方法
- 添加正确的Spring bean后处理器
@Configuration publicclassSpringConfiguration{ ... @Bean publicstaticMethodValidationPostProcessormethodValidationPostProcessor(){ returnnewMethodValidationPostProcessor(); } }
- 请享用! 真的,结束了,您可以按合同使用设计来满足您的内心需求。
本文来源可以在Eclipse / Maven的格式可以找到这里 。
更进一步 :请参阅文章中的相关链接
该博客的普通读者可能已经注意到我正在使用Spring Java配置,而我以前是XML配置的倡导者。 请阅读这篇文章。
翻译自: https://blog.frankel.ch/design-by-contract-and-bean-validation/