如何删除大的if-else-if链
可能重复:
Java中if语句的长列表
我的任务是处理一些代码,并且有一个巨大的if-else-if链(100+ else-ifs)检查字符串。
有什么好的技术可以更新这段代码,以确定if-else-if链可以缩小到更易于管理的地方。
链看起来像这样:
if(name.equals("abc")){ do something } else if(name.equals("xyz")){ do something different } else if(name.equals("mno")){ do something different } ...... ..... else{ error }
您可以将每个分支中的代码提取到单独的方法,然后将这些方法转换为公共基本接口的实现(让我们称之为Handler
)。 之后,您可以填充Map
,只需查找并执行给定字符串的正确处理程序。
不幸的是,为接口实现100多个子类需要相当多的样板代码,但目前在Java中没有更简单的方法来实现这一点。 将案例实现为Enum
元素可能有所帮助 – 这是一个例子 。 理想的解决方案是使用闭包/ lambda,但是我们必须等到Java 8 …
一些选择/想法:
- 保持原样 – 它没有从根本上打破,并且相当清晰和易于维护
- 使用switch语句(如果您使用的是Java 7) – 不确定这是否会让您获益匪浅
- 为函数对象创建String的HashMap,其中函数对象实现所需的行为作为方法。 那么你的调用代码就是:
hashMap.get(name).doSomething();
- 通过对字符串进行子分组将其分解为函数调用的层次结构 。 你可以通过依次取每个字母来做到这一点,所以一个分支处理所有以’a’开头的名字等。
- 重构,以便您不将名称作为String传递,而是传递命名对象。 然后你可以做
namedObject.doSomething()
使用Enums,您可以为每个实例创建一个方法。
public enum ActionEnum { ABC { @Override void doSomething() { System.out.println("Doing something for ABC"); } }, XYZ { @Override void doSomething() { System.out.println("Doing something for XYZ"); } }; abstract void doSomething(); } public class MyActionClass { public void myMethod(String name) { ActionEnum.valueOf("ABC").doSomething(); } }
它仍然有点凌乱(大型枚举有100多个条目,即使它只是调度),但可能会避免使用HashMap初始化代码(在我看来,100 + puts也很混乱)。
而另一种选择(用于文档目的)将是反映:
public interface Action { void doSomething(); } public class ABCAction implements Action { @Override public void doSomething() { System.out.println("Doing something for ABC"); } } public class MyActionClass { void doSomethingWithReflection(String name) { try { Class extends Action> actionClass = Class. forName("actpck."+ name + "Action").asSubclass(Action.class); Action a = actionClass.newInstance(); a.doSomething(); } catch (Exception e) { // TODO Catch exceptions individually and do something useful. e.printStackTrace(); } } }
每种方法都有它的权衡:
- HashMap = Fast + Kinda messy(“设置”代码有数百个put)
- Enum = Fast + Kinda messy 2(巨大的文件)。
- reflection=较慢+运行时容易出错,但提供干净的分离而无需使用笨重的大HashMap。
就像Matt Ball在评论中所说,你可以使用命令模式。 定义Runnable类的集合:
Runnable task1 = new Runnable() { public void run() { /* do something */ } }; Runnable task2 = // etc.
然后,您可以使用键中的映射到runnables:
Map taskMap = new HashMap(); taskMap.put("abc", task1); taskMap.put("xyz", task2); // etc.
最后,将if-else链替换为:
Runnable task = taskMap.get(name); if (task != null) { task.run(); } else { // default else action from your original chain }
您可以使用switch语句,但是在Java SE 7中实现了带有String案例的Switch语句
最好的解决方案是使用命令模式
这是一个流行的箭头反模式 ,杰夫讨论了一些处理这个非常好的方法在他的post。