Java 在验证类中使用哪种设计模式来避免if/else?
我目前正在使用HibernateContrantValidator来实现我的验证。但是我的审阅者不喜欢在代码或中使用if/else!接线员。我可以使用哪种设计模式删除验证逻辑中的if/elseJava 在验证类中使用哪种设计模式来避免if/else?,java,design-patterns,hibernate-validator,spring-validator,Java,Design Patterns,Hibernate Validator,Spring Validator,我目前正在使用HibernateContrantValidator来实现我的验证。但是我的审阅者不喜欢在代码或中使用if/else!接线员。我可以使用哪种设计模式删除验证逻辑中的if/else public class SomeValidatorX implements ConstraintValidator<SomeAnnotation, UUID> { @Autowired SomeRepository someRepository;
public class SomeValidatorX implements ConstraintValidator<SomeAnnotation, UUID> {
@Autowired
SomeRepository someRepository;
@Override
public boolean isValid(UUID uuid, ConstraintValidationContext context) {
return !(uuid!=null && someRepository.existsById(uuid)); //The reviewer doesn't want this negation operator
}
}
公共类SomeValidatorX实现ConstraintValidator{
@自动连线
一些知识库一些知识库;
@凌驾
公共布尔值有效(UUID UUID,ConstraintValidationContext){
return!(uuid!=null&&someRepository.existsById(uuid));//审阅者不需要此否定运算符
}
}
在下面的代码中,他不想要if/else
public class SomeValidatorY implements ConstraintValidator<SomeAnnotation, SomeClass> {
@Autowired
SomeRepository someRepository;
@Override
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
if(someObject.getFieldA() != null) { //He doesn't want this if statement
//do some operations
List<Something> someList = someRepository.findByAAndB(someObject.getFieldA(),B);
return !someList.isEmpty(); //He doesn't want this ! operator
}
return false; // He was not fine with else statement in here as well
}
}
公共类SomeValidatorY实现ConstraintValidator{
@自动连线
一些知识库一些知识库;
@凌驾
公共布尔值有效(SomeClass someObject,ConstraintValidationContext){
if(someObject.getFieldA()!=null){//他不想要这个if语句
//做一些手术
List-someList=someRepository.findByAAndB(someObject.getFieldA(),B);
return!someList.isEmpty();//他不想要这个!运算符
}
return false;//他对这里的else语句也不满意
}
}
旁注:我们必须使用领域驱动设计(如果有帮助的话)很久以前,在一开始的时候。有一个指导方针说,方法应该只有一个退出点。为了实现这一点,开发人员必须跟踪本地状态,并使用if/else来达到方法的末尾 今天我们知道得更多了。通过尽可能早地退出一个方法,在阅读代码时,将整个流程保存在我们的头脑中会容易得多。更简单的代码意味着更少的错误。少犯错误等于少犯错误 在我看来,这就是为什么审阅者不喜欢代码。这本书读起来并不容易 让我们举第一个例子:
public boolean isValid(UUID uuid, ConstraintValidationContext context) {
return !(uuid!=null && someRepository.existsById(uuid)); //The reviewer doesn't want this negation operator
}
代码说的是“不是这个:(uuid不应该是空的,它必须存在)”。这容易理解吗?我想不是
另一种选择是:“如果uuid不存在就可以了,但如果存在,则该项可能不存在”
或在代码中:
if (uuid == null) return true;
return !someRepository.existsById(uuid);
更容易阅读,对吗?(我希望我的意图是正确的;)
第二个示例
if(someObject.getFieldA() != null) { //He doesn't want this if statement
//do some operations
List<Something> someList = someRepository.findByAAndB(someObject.getFieldA(),B);
return !someList.isEmpty(); //He doesn't want this ! operator
}
return false; // He was not fine with else statement in here as well
在C#中,我们有Any()
,它与isEmpty相反,在这种情况下,我更喜欢它,因为它删除了否定
有时需要否定。在存储库中编写一个新方法来避免它是没有意义的。但是,如果findByAAndB
仅用于此,我会将其重命名为ensurerecombination(a,b)
,以便在有效情况下返回true
试着边说边写代码,这样就更容易在脑海中描绘代码。你不是说“我不饱,我们去吃午饭吧”,是吗 您可以检查空对象模式。
一般的模式是从代码中完全禁止null
。这消除了难看的null
检查。在这一点上,我同意您的代码审阅者的看法
以下建议将导致:
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}
避免空检查
在引入空对象模式之前,只需应用模式或约定来强制初始化所有引用。这样,您可以确保整个代码中没有null
引用。
因此,当您遇到NullPointerException
时,您不会通过引入null
检查来解决问题,而是通过初始化引用(在构造时),例如使用默认值、空集合或空对象来解决问题
大多数现代语言都支持通过注释(如@NonNull
)进行代码分析,该注释检查参数等引用,并在参数null
/未初始化时引发异常<例如,code>javax.annotation
提供了这样的注释
public void operation(@NonNull Object param) {
param.toString(); // Guaranteed to be not null
}
使用这样的注释可以防止库代码出现空参数
空对象模式
不是使用null
引用,而是使用有意义的值或专用的null对象初始化每个引用:
class NullAccount extends Account implements NullObject {
// Initialize ALL attributes with meaningful and *neutral* values
public NullAccount() {
setValue(0); //
setOwners(new ArrayList<Owner>())
@Override
public boolean getIsNull() {
return true;
}
}
定义空对象协定(非必需):
定义基本类型:
abstract class Account {
private double value;
private List<Owner> owners;
// Getters/setters
}
使用NullAccount
类初始化所有Account
引用:
class Employee {
private Account Account;
public Employee() {
setAccount(new NullAccount());
}
}
或者使用NullAccount
返回失败状态实例(或默认值),而不是返回null
:
public Account findAccountOf(Owner owner) {
if (notFound) {
return new NullAccount();
}
}
public void testNullAccount() {
Account result = findAccountOf(null); // Returns a NullAccount
// The Null-object is neutral. We can use it without null checking.
// result.getOwners() always returns
// an empty collection (NullAccount) => no iteration => neutral behavior
for (Owner owner : result.getOwners()) {
double total += result.getvalue(); // No side effect.
}
}
public boolean tryFindInText(String source, String searchKey, SearchResult result) {
int matchIndex = source.indexOf(searchKey);
result.setMatchIndex(matchIndex);
return matchIndex > 0;
}
public void useTryDo() {
SearchResult result = new Searchresult();
if (tryFindInText("Example text", "ample", result) {
int index = result.getMatchIndex();
}
}
试做模式
您可以使用的另一个模式是Try-Do模式。您只需测试操作本身,而不是测试操作的结果。操作负责返回操作是否成功
在文本中搜索字符串时,无论是否找到结果,都可以返回布尔值,而不是返回空字符串或更糟的null
:
public Account findAccountOf(Owner owner) {
if (notFound) {
return new NullAccount();
}
}
public void testNullAccount() {
Account result = findAccountOf(null); // Returns a NullAccount
// The Null-object is neutral. We can use it without null checking.
// result.getOwners() always returns
// an empty collection (NullAccount) => no iteration => neutral behavior
for (Owner owner : result.getOwners()) {
double total += result.getvalue(); // No side effect.
}
}
public boolean tryFindInText(String source, String searchKey, SearchResult result) {
int matchIndex = source.indexOf(searchKey);
result.setMatchIndex(matchIndex);
return matchIndex > 0;
}
public void useTryDo() {
SearchResult result = new Searchresult();
if (tryFindInText("Example text", "ample", result) {
int index = result.getMatchIndex();
}
}
在您的特殊情况下,可以使用containsAndB():boolean
实现替换findByAAndB()
组合模式 最终的解决方案实现空对象模式并重构find方法。由于您想测试
A
和B
的存在性,原始findByAAndB()
的结果以前被丢弃。另一种方法public boolean contains()
将改进您的代码。重构后的实现如下所示:
abstract class FieldA {
}
class NullFieldA {
}
class FieldAImpl {
}
class SomeClass {
public SomeClass() {
setFieldA(new NullFieldA());
}
}
改进的验证:
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}
听起来像是你的代码审查员应该回答的问题,如果他们提出要求,也许这里的一些东西可以帮助你。看起来好像不是if/else有问题,在这种情况下,你应该问审查员为什么。他只是含糊地要求我为这个场景确定合适的设计模式。或者想出我自己的模式。老实说,我只知道一些设计模式。但不完全确定是什么
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}