提高条件陈述的易读性

时间:2013-09-12 08:19:50

标签: java android readability code-readability

我正在为我的Android设备构建一个HTTP服务器。

我使用了很多IF-ELSE语句来处理不同的请求。

由于我将与其他人分享我的代码供以后使用,我必须尽可能清晰。现在,我甚至无法轻松阅读我的代码。

我认为问题来自于在一个类中使用大量IF-ELSE语句。 例如。

if(purpose.equals("readProfile"){
     .....
}
else if(purpose.equals("writeProfile"){
     .....
}
    ....

我尝试在类别中对它们进行分类,并根据类别对条件进行排序。但并没有提高很多的可用性。 然后我尝试在每个条件面前写短评。但这让事情变得更加混乱。

如何提高条件语句的易读性?

5 个答案:

答案 0 :(得分:4)

正如Luiggi Mendoza所述,这是对a previous question ...

的跟进

如果您使用的是 Java 7 ,则可以使用switch-case statement for strings

    //month is a String
    switch (month.toLowerCase()) {
        case "january":
            monthNumber = 1;
            break;
          //partsleft out for sake of brevity ..
        default: 
            monthNumber = 0;
            break;
    }

(摘自上面引用的Oracle Java教程。)

重构

然而,这个巨大的if-else只是问题的一部分。由于这似乎是一个随着时间的推移而增长的结构,我建议进行彻底的重构,并使用我认为的Strategy pattern。你应该:

制定涵盖所有用例边界的界面:

interface MyStrategy {
  void execute(MyInputContext input, MyOutputContext output);
}

(使用带有MyInputContext和MyOutputContext的void方法只是一种方法,这只是一个示例,但是为了处理具有响应的请求,这有意义,就像Servlet的工作方式一样)

将大IF-ELSE语句的内容重构为此接口的实例(这些将是策略):

//VERY simplified...
class ReadProfileStrategy implements MyStrategy {
  void execute(MyInputContext input, MyOutputContext output) {
    //do the stuff that was in the if-else block in the "readProfile" part
  }
}

//... at the branching part:
MyInputContext input; //build this here
MyOutputContext output; //build this here

switch (purpose) {
    case "readProfile":
         // no need to always instantiate this, it should be stateless...
         new ReadProfileStrategy().execute();
         break;
    //... left out for sake of brevity
}

重构步骤2

如果这样做,您可以将字符串ID添加到接口,并将实例本身添加,并完全删除if-else或switch语句,您可以创建一个甚至通过IOC容器填充的Map(如) ,是最新的,并且完全灵活。

class ReadProfileStrategy implements MyStrategy {
  String getID() {
      return "readProfile";
  }

  void execute(MyInputContext input, MyOutputContext output) {
    //do the stuff that was in the if-else block in the "readProfile" part
  }
}

在处理请求的类中

private final Map<String, MyStrategy> strategyMap; //fill the map using your favorite approach, like using Spring application context, using the getCode() to provide the key of the map

在处理逻辑中:

MyStrategy strategy = strategyMap.get(purpose);
if(strategy!=null) {
    strategy.execute();
}
else {
    //handle error here
}

答案 1 :(得分:2)

这可能超出了范围,只是一个观察

尝试使用

if("readProfile".equals(purpose){}而不是

if(purpose.equals("readProfile"){}

这将有助于避免null pinter异常

答案 2 :(得分:2)

枚举可以提供帮助 - 您还可以为它们添加功能。

public void test(String purpose) {
  if (purpose.equals("readProfile")) {
    // Read.
  } else if (purpose.equals("writeProfile")) {
    // Write.
  }
}

enum Purpose {
  readProfile {
    @Override
    void doIt() {
      // Read.
    }
  },
  writeProfile {
    @Override
    void doIt() {
      // Write.
    }
  };

  abstract void doIt();

}
public void test2(String purpose) {
  Purpose.valueOf(purpose).doIt();
}

答案 3 :(得分:1)

您可以尝试使用某种Action-Interface和每个块的实现,并使用具体的此操作实现预加载地图。

interface Action {
    void execute();
}

Map<String, Action> actions = new HashMap<>();
actions.put("readProfile", new Action() { ... });
actions.put("writeProfile", new Action() { ... });

actionMap.get(purpose).execute();    

这也会降低你的圈复杂度。当然你应该只预加载一次地图。

答案 4 :(得分:1)

好吧,如果将if-else条件中的代码分离到另一个类是有意义的,也许使用Factory模式。还要使所有单独的类使用MyActivity.class等方法实现公共接口(例如:execute())。

工厂决定必须根据您传递的字符串创建哪个对象(ReadProfile.classWriteProfile.class等),然后调用execute()方法。

MyActivity obj = MyFactory.createMyActivity(String)
obj.execute(...);