如何在if条件下重构一个复杂的表达式?

时间:2014-01-22 05:24:33

标签: java if-statement enums refactoring polymorphism

以下是示例:

if (folderInfoRecord.getValueRequired()
    && ((!folderInfoData.getInfoType().equals(InfoType.NUMERIC) 
    && !folderInfoData.getInfoType().equals(InfoType.DATE) 
    && !folderInfoData.getInfoType().equals(InfoType.CHOOSE) 
    && StringUtils.isBlank(folderInfoRecord.getInfoValue(), true))
    || (folderInfoData.getInfoType().equals(InfoType.NUMERIC) 
    && folderInfoRecord.getInfoValueNumeric() == null) 
    || (folderInfoData.getInfoType().equals(InfoType.DATE) 
    && folderInfoRecord.getInfoValueDateTime() == null) 
    || (folderInfoData.getInfoType().equals(InfoType.CHOOSE) 
    && folderInfoData.getSelectedInfoRole() == null))) {
        showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
        return;
}

任何人都可以告诉我如何优化这个条件吗?

5 个答案:

答案 0 :(得分:2)

通过优化,如果你的意思是运行时的复杂性,我说的并不多,因为我并不是每个方法都做的最模糊的事情。 我强烈建议不要像你正在展示的意大利面条代码。对于令人困惑的NOT和OR,我会避免在if语句中计算.equals或.isBlank。在

之外有一些外部布尔标志
bool folderDataisNumeric = folderInfoData.getInfoType().equals(InfoType.NUMERIC) 

然后只需使用标志!folderDataisNumeric将使代码更具人性化。

我的两分钱,无论如何。

答案 1 :(得分:2)

final String info = folderInfoData.getInfoType();
final boolean isNumeric = info.equals(InfoType.NUMERIC);
final boolean isDate = info.equals(InfoType.DATE);
final boolean isChoose = info.equals(InfoType.CHOOSE);
final boolean isBlank = StringUtils.isBlank(folderInfoRecord.getInfoValue(), true);

if (folderInfoRecord.getValueRequired() && 
    ((!isNumeric && !isDate && !isChoose && isBlank)
    || (isNumeric && folderInfoRecord.getInfoValueNumeric() == null) 
    || (isDate && folderInfoRecord.getInfoValueDateTime() == null) 
    || (isChoose && folderInfoData.getSelectedInfoRole() == null))) {

    showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
    return;
}

答案 2 :(得分:1)

您还可以在此处拆分if逻辑以使其更具可读性。或者,我建议你创建一个将执行所有这些检查并返回false的函数。这样您就不必将所有支票放在一个位置。您不会通过我建议的任何方法获得任何性能优势,但它将更具可读性。

<强> Approach1:

infoType = folderInfoData.getInfoType();

if (folderInfoRecord.getValueRequired())
{
    if ((!infoType.equals(InfoType.NUMERIC) && !infoType.equals(InfoType.DATE) && !infoType.equals(InfoType.CHOOSE) && StringUtils.isBlank(folderInfoRecord.getInfoValue(), true)))
    {
       showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
       return;
    }
    if((infoType.equals(InfoType.NUMERIC) && folderInfoRecord.getInfoValueNumeric() == null))
    {
       showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
       return;
    }
    if(infoType.equals(InfoType.DATE) && folderInfoRecord.getInfoValueDateTime() == null)
    {
       showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
       return;
    }
    if(infoType.equals(InfoType.CHOOSE) && folderInfoData.getSelectedInfoRole() == null)
    {
       showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
       return;
    }
}

方法2:

if(checkConditions(folderInfoData,folderInfoRecord) == true)
{
     showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
     return;
}


public bool checkConditions(Object folderInfoData, Object folderInfoRecord)
{
     infoType = folderInfoData.getInfoType();

    if (folderInfoRecord.getValueRequired())
    {
        if ((!infoType.equals(InfoType.NUMERIC) && !infoType.equals(InfoType.DATE) && !infoType.equals(InfoType.CHOOSE) && StringUtils.isBlank(folderInfoRecord.getInfoValue(), true)))
        {
           return true;
        }
        if((infoType.equals(InfoType.NUMERIC) && folderInfoRecord.getInfoValueNumeric() == null))
        {
           return true;
        }
        if(infoType.equals(InfoType.DATE) && folderInfoRecord.getInfoValueDateTime() == null)
        {
           return true;
        }
        if(infoType.equals(InfoType.CHOOSE) && folderInfoData.getSelectedInfoRole() == null)
        {
           return true;
        }
    }
    return false;
}

您可以通过在启动if分支之前执行infoType.equals检查来进一步优化它,并将它们存储在布尔逻辑中以进一步简化它。其他答案中已经给出了这方面的例子。通过将这种方法与其他方法结合使用,我认为代码会更好。另请注意,必须将对象类型更改为对象类型才能使此代码生效。我只是把它作为例子,因为我不知道你的对象的类型是什么。

答案 3 :(得分:1)

好吧,如果我正确读这个,这将减少到不超过4个函数调用,以确定是否需要引发警报。所以至少少了一点......快一点。

哦,是的,也可读。

更新:

folderInfoData.getInfoType()无需无条件地对所有3种类型进行评估,修改后即可反映出来。仍然可读。

if(folderInfoRecord.getValueRequired())
{
   Boolean alertNeeded = false;

   if(folderInfoData.getInfoType().equals(InfoType.NUMERIC)) 
   {
      if(folderInfoRecord.getInfoValueNumeric() == null) alertNeeded = true;
   }
   else if(folderInfoData.getInfoType().equals(InfoType.DATE))
   {  
      if(folderInfoRecord.getInfoValueDateTime() == null) alertNeeded = true;
   }
   else if(folderInfoData.getInfoType().equals(InfoType.CHOOSE))
   {
      if(folderInfoData.getSelectedInfoRole() == null) alertNeeded = true;
   }
   else
   {
      if(StringUtils.isBlank(folderInfoRecord.getInfoValue(), true))
         alertNeeded = true;
   }

   if(alertNeeded) 
   { 
      showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
      return;
   }
}

答案 4 :(得分:1)

真正的解决方案是Replace Conditional with Polymorphism。这里最大的问题是标志是编码类型。


我知道它可能需要大量的工作,而你可能无法做到这一点。 这是一种解决方法,它使代码的意图更清晰,代码更具可读性:

if (folderInfoRecord.getValueRequired() && 
    Checker.isMissing(folderInfoData, folderInfoRecord) 
{
        showNotification(pageResourceBundle.getText("JS_ALERT_FIELD_REQUIRED"));
        return;
}

(下面的代码甚至可能无法编译,请查看原始代码。)

final class Checker {

  InfoType         it;
  FolderInfoRecord fir;
  FolderInfoData   fid;

  private Checker(FolderInfoData fid, FolderInfoRecord fir) {
    this.it  = fid.getInfoType();
    this.fid = fid;
    this.fir = fir;
  }

  static public boolean isMissing(FolderInfoData fid, FolderInfoRecord fir) {

      return (new Checker(fid, fir)).isMissing();
  }

  private boolean isMissing() {

     return wrongAsNumeric() && wrongAsDate() && wrongAsChoose() && isBlank();
  }

  private boolean wrongAsNumeric() {

    return it.equals(InfoType.NUMERIC) && (fir.getInfoValueNumeric() == null);
  }

  private boolean wrongAsDate() {

    return it.equals(InfoType.DATE) && (fir.getInfoValueNumeric() == null);
  }

  private boolean wrongAsChoose() {

    return it.equals(InfoType.CHOOSE) && folderInfoData.getSelectedInfoRole() == null)
  }

  private boolean isBlank() {

    return StringUtils.isBlank(folderInfoRecord.getInfoValue(), true);
  }  
}

与其他提议的解决方案不同,此代码可重复使用:如果您要在代码中的其他位置执行此检查,只需调用Checker.isMissing()