【问题标题】:What approach/method to use instead of multiple if statements使用什么方法/方法而不是多个 if 语句
【发布时间】:2014-02-06 15:50:10
【问题描述】:

我有一个 Java Web 应用程序,它要求用户在 4 个选项之间进行选择。他们可以选择 1 个、全部或 5 个选项的任意组合。他们的选择被读入一个带有真/假值的 Hashmap。如果选择了该选项,则为真,未选择为假。根据用户的选择,从要处理的资源文件夹中选择不同的文件。我的问题是代码只是一团糟的逻辑,我确信有一种更简单的方法来实现它。以下是我的问题的虚拟代码。

public class offerSelector {

public void selectOffer(Map params) {

/* Map params = Map<String, String> params = new HashMap <>();
   It contains values ("internet","true),("phone","true"),("tv","true"),("cell","true")
*/

boolean option_1 = params.get("internet");
boolean option_2 = params.get("phone");
boolean option_3 = params.get("tv");
boolean option_4 = params.get("cell");

File offer = null;

if (option_1 == true && option_2 == false && option_3 == false && option_4 == false) {
    offer = new File("internet_order");
}
else if(option_1 == false && option_2 == true && option_3 == false && option_4 == false) {
    offer = new File("phone_order");
}

//continues like so with all possible combinations
else if(option_1 == true && option_2 == true && option_3 == true && option_4 == true) {
    offer = new File("all_elements_order");
}

processOrder(offer);
}
}

【问题讨论】:

  • 首先是错误的操作符。使用==。甚至不使用它。在 Java 中,您可以只说 if(option_1),前提是 option_1 是一个布尔字段。
  • 抱歉,这只是我拼凑的代码。我的实际代码中的语法是正确的(我知道是因为它有效:))
  • 那么请贴出正确的代码。
  • 老兄!你的代码搞砸了。 option_1 = true 将失败,因为您没有使用 == 并且 option_1 不是布尔值。
  • 每个组合真的有不同的文件吗?这似乎很奇怪。

标签: java if-statement hashmap logic


【解决方案1】:

我非常喜欢将此解析推入自定义对象,例如

public class SomeObject
{
  public SomeObject(Values)
  {
     this.options1 = //Something
     this.options2 = //Something
     this.options3 = //Something
     this.options4 = //Something
  }

  public boolean isPhone() {return option1 && option2 && option3 && !option4;}
}

然后,当您使用该选项时,您可以这样做:

var x = new SomeObject(Values);
if (x.isPhone) {
  // DO IS PHONE Branch
}
if (x.isFax) {
  // DO IS Fax Branch
}

这更好,因为解析逻辑被排除在具有单一职责的单个类中。然后在您的 if 块中清楚您正在查看的内容。

其他选项是从 SomeObject 类返回一个 Enum 并使用真正的 case/switch 语句。

【讨论】:

    【解决方案2】:

    有很多解决方案。例如以下。

    定义interface Action

     interface Action {
         boolean apply(Map<String, String> params);
         void perform(Map<String, String> params);
     }
    

    定义枚举操作:

     enum Actions implement Action {
          ONE {
                boolean apply(Map<String, String> params) {/*implement it*/}
                void perform(Map<String, String> params) {/*implement it*/}
          },
          TWO {
                boolean apply(Map<String, String> params) {/*implement it*/}
                void perform(Map<String, String> params) {/*implement it*/}
          },
          ;
          //etc.
     }
    

    在回调方法中实现您的逻辑。显然给枚举常量正常名称。

    现在您的代码可能如下所示:

    public void selectOffer(Map params) {
        for (Actions a : Actions.values()) {
            if (a.apply(params)) {
                 return a.perform(params);
            }
        }
     }
    

    【讨论】:

    • 这有助于重复逻辑。但实际上在 implement it 内部,您将拥有相同的 if-combinations 样板,被提问者想要摆脱。
    【解决方案3】:

    您可以尝试使用自定义对象,比如Options

    //note that a lot of common stuff like constructors or modifiers are stripped for simplicity
    class Options {
      boolean internet;
      boolean phone;
      ...
    
      public void equals( Object other) {
        return other != null && 
         other.getClass().equals( getClass()) && 
         other.internet == this.internet && 
         other.phone == this.phone &&
         ...
      }    
    
      public int hashCode() {
        //left for your excerise, should match equals
      }
    }
    
    Map<Options, File> files = ...; //create and fill
    

    然后解析布尔参数并创建一个Options 实例,用于在地图中查找文件,例如:

     Options paramOptions = new Options(/*booleans parsed from params*/);
     offer = files.get( paramOptions  );
    

    【讨论】:

      【解决方案4】:

      使用二进制表示法。每个位代表一个选项:

      option4为true,option3为true,option2为false,option1为false为1100

      1100 bin = 12 月 12 日。

      每个组合代表一个十进制数,您可以在switch 语句中使用它。

      希望你明白我的意思。

      【讨论】:

      • 如果使用枚举或常量(如public final int INTERNET = 0x01;)代表每一位会更好。
      • 这是真的!结合它,一个 enmu 会使其更具可读性
      【解决方案5】:

      把它全部封装起来。隐藏在另一个类的胆量中筛选选项排列的细节。像这样的……

      //controller code
      Boolean internet= params.get("internet");
      Boolean phone = params.get("phone");
      Boolean tv= params.get("tv");
      Boolean cell = params.get("cell");    
      File offer = FileHelper(internet, phone, tv, cell);
      //end controller code ...
      
      
      public class FileHelper {
      
      private final String PHONE = "phone_order";
      private final String INTERNET= "internet_order";
      private final String CELL= "cell_order";
      private final String TV = "tv_order";
      private final String ALL = "all_elements_order";
      
      private boolean[] options;
      
      public FileHelper(Boolean phone, Boolean internet, Boolean cell, Boolean tv) {
          options = new boolean[4];
          options[0] = phone == null ? false : phone;
          options[1] = internet == null ? false : internet ;
          options[2] = cell== null ? false : cell;
          options[3] = tv == null ? false : tv ;
      }
      
      public File getOffer() {
          File f;
          if ( includeAll()) f = new File(ALL);
          if ( phoneOffer()) f = new File(PHONE);
          if ( internetOffer()) f = new File(INTERNET);
          // .... and so on
      
          return f;
      }
      
      private boolean includeAll() {
          for(boolean b : options) {
              if (!b) return false;
          }
          return true;
      }
      
      private boolean internetOffer() {
          return getSingleOption() == 1;    
      }
      
      private boolean phoneOffer() {
          return getSingleOption() == 0;   
      }
      
      private int getSingleOption() {
          int i = -1;
      
          for(int j; j =0; j++) {
              if(options[j]) {
                  if ( i >= 0) {
                      return -1; //user has selected > 1 option
                  } else {
                     i = j;
                  }
              }            
          }
          return i;
      }
      
      }
      

      我猜 boolean[] 不会流行,但我认为拥有这样的结构可以让您轻松确定用户标记为真的选项的数量,从您的问题来看,这似乎是您的问题我想知道。

      【讨论】:

        【解决方案6】:

        抱歉没有足够的声誉发表评论, 首先你可以使用开关:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html,这样的代码更容易,也许对于组织你可以使用从这个启动的另一个函数(只要记住把那个字符串放在通用)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多