Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在验证类中使用哪种设计模式来避免if/else?_Java_Design Patterns_Hibernate Validator_Spring Validator - Fatal编程技术网

Java 在验证类中使用哪种设计模式来避免if/else?

Java 在验证类中使用哪种设计模式来避免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;

我目前正在使用HibernateContrantValidator来实现我的验证。但是我的审阅者不喜欢在代码或中使用if/else!接线员。我可以使用哪种设计模式删除验证逻辑中的if/else

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);
}