如何删除大的 if-else-if 链

发布于 2024-12-03 11:36:52 字数 529 浏览 2 评论 0原文

可能的重复:
Java 中 if 语句的长列表

我的任务是处理一些代码,并且有一个巨大的 if-else-if 链(100 多个 else-if)来检查字符串。

有哪些好的技术可以更新此代码,以便将 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
}

Possible Duplicate:
Long list of if statements in Java

I was tasked to work with some code, and there is a giant if-else-if chain (100+ else-ifs) that checks Strings.

What are some good techniques to update this code as to where the if-else-if chain can be shrunken down to something much more manageable.

The chain looks something like this:

if(name.equals("abc")){
    do something
} else if(name.equals("xyz")){
    do something different
} else if(name.equals("mno")){
    do something different
} ......
.....
else{ 
   error
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

独自唱情﹋歌 2024-12-10 11:36:52

您可以将每个分支中的代码提取到一个单独的方法中,然后将这些方法转换为公共基本接口的实现(我们称之为Handler)。之后,您可以填充 Map 并查找并执行给定字符串的正确处理程序。

不幸的是,接口的 100 多个子类的实现需要相当多的样板代码,但目前 Java 中没有更简单的方法来实现这一点。将案例实现为 Enum 的元素可能会有所帮助 - 此处是一个例子。理想的解决方案是使用闭包/lambda,但遗憾的是我们必须等到 Java 8 才能实现这一点......

You can extract the code in each branch to a separate method, then turn the methods into implementations of a common base interface (let's call it Handler). After that, you can fill a Map<String, Handler> and just look up and execute the right handler for given string.

Unfortunately the implementation of 100+ subclasses for the interface requires quite a lot of boilerplate code, but currently there is no simpler way in Java to achieve this. Implementing the cases as elements of an Enum may help somewhat - here is an example. The ideal solution would be using closures / lambdas, but alas we have to wait till Java 8 for that...

相思碎 2024-12-10 11:36:52

一些选项/想法:

  • 保持原样 - 它没有从根本上被破坏,并且相当清晰且易于维护
  • 使用 switch 语句(如果您使用的是 Java 7) - 不确定这是否会给您带来很多好处,
  • 创建字符串到 FunctionObjects 的 HashMap,其中函数对象将所需的行为作为方法实现。那么您的调用代码就是: hashMap.get(name).doSomething();
  • 通过对字符串进行子分组,将其分解为函数调用的层次结构。您可以通过依次获取每个字母来做到这一点,这样一个分支就会处理所有以“a”等开头的名称。
  • 重构,这样您就不会将名称作为字符串传递,而是传递一个命名的名称目的。然后你就可以做 namedObject.doSomething()

Some options / ideas:

  • Leave it as it is - it's not fundamentally broken, and is reasonably clear and simple to maintain
  • Use a switch statement (if you are using Java 7) - not sure if this gains you much though
  • Create a HashMap of String to FunctionObjects where the function objects implement the required behaviour as a method. Then your calling code is just: hashMap.get(name).doSomething();
  • Break it into a heirarchy of function calls by sub-grouping the strings. You could do this by taking each letter in turn, so one branch handles all the names starting with 'a' etc.
  • Refactor so that you don't pass the name as a String but instead pass a named object. Then you can just do namedObject.doSomething()
倾`听者〃 2024-12-10 11:36:52

就像马特·鲍尔在他的评论中所说的那样,您可以使用命令模式。定义 Runnable 类的集合:

Runnable task1 = new Runnable() {
    public void run() { /* do something */ }
};
Runnable task2 = // etc.

然后您可以使用从键​​到 runnables 的映射:

Map<String,Runnable> taskMap = new HashMap<String,Runnable>();
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
}

Like Matt Ball said in his comment, you can use a command pattern. Define a collection of Runnable classes:

Runnable task1 = new Runnable() {
    public void run() { /* do something */ }
};
Runnable task2 = // etc.

Then you can use a map from your keys to runnables:

Map<String,Runnable> taskMap = new HashMap<String,Runnable>();
taskMap.put("abc", task1);
taskMap.put("xyz", task2);
// etc.

Finally, replace the if-else chain with:

Runnable task = taskMap.get(name);
if (task != null) {
    task.run();
} else {
    // default else action from your original chain
}
抚你发端 2024-12-10 11:36:52

使用枚举,您可以为每个实例拥有一个方法。

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 多个 put 也很混乱)。

还有另一种选择(出于文档目的)是反射:

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 = 快速 + 有点混乱(具有数百个放置的“设置”代码)
  • Enum = 快速 + 有点混乱 2(巨大的文件)。
  • 反射 = 较慢 + 运行时容易出错,但可以提供干净的分离,而无需求助于笨重的大 HashMap。

With Enums, you can have a method per instance.

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

}

It is still kinda messy (big enum with 100+ entries, even it all it does is dispatching), but may avoid the HashMap initialization code (100+ puts is also messy in my opinion).

And yet another option (for documentation purposes) would be reflection:

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

Each approach has it's trade offs:

  • HashMap = Fast + Kinda messy ("set-up" code with hundred of puts)
  • Enum = Fast + Kinda messy 2 (huge file).
  • Reflection = Slower + runtime error prone, but provides clean separation without resorting to clunky big HashMap.
魂牵梦绕锁你心扉 2024-12-10 11:36:52

您可以使用 switch 语句,但带有字符串大小写的 Switch 语句已在 Java SE 7 中实现

最好的解决方案是使用命令模式

you can use the switch statement , but Switch statements with String cases have been implemented in Java SE 7

the best solution is to use the command pattern

多情出卖 2024-12-10 11:36:52

这是一种流行的 Arrow 反模式,Jeff 在他的文章中讨论了一些很好地处理这个问题的方法此处

This is a popular Arrow Anti-Pattern and Jeff discusses some approaches to handle this very nicely in his post here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文