字符串输入,指定调用哪个函数[Java] [最佳实践]

时间:2015-07-06 21:02:41

标签: java string function user-input

应用程序

我正在编写一个根据用户输入执行某些功能的应用程序。 例如。如果用户输入是 “1 2添加”输出将为“3”。 我的目标是实现许多这样的方法(div,modulo等)。当我的扫描仪识别出像“添加”这样的函数名时,应该调用函数“add()”。

我的方式

我这样做的方法是让一个FunctionHandler类来评估输入。

主:

String inputCommand = sc.nextCommand();
functionHandler.handle(inputCommand);

功能处理程序:

public class FunctionHandler {

   public void handle (String functionName) {
      if (functionName.equals("add")) {
          add();
      } else if (functionName.equals("div") {
          div();
      }
   }
   private void add() {
   .......
   }
   ....

}

那个问题

当我添加越来越多的函数时,if语句变得非常大,当然还有FunctionHandler类。此外,每当我添加一个新函数时,我都必须在两个地方更改代码:我必须定义函数,然后在handle()中添加else if子句来调用该函数。这意味着应该封装的两条信息彼此完全独立地“存储”。 我想知道解决这种情况的最佳做法是什么?

我的想法

我正在考虑使用枚举,但在这种情况下它们似乎不太合适。

我的另一个想法是创建一个接口 Function ,然后为实现 Function 的每个函数创建一个类。该接口有两种方法:

  • 的getName()
  • 执行()
  • 然后我可以在 FunctionHandler 中创建一个(手动) Functions 的数组,通过它我可以循环查看用户输入的命令是否与getName()匹配。 但是,为每个函数设置一个不同的类也不是很干净,并且它也没有摆脱我要添加的每个函数的问题,我必须在两个地方执行它:类和数组。

    这个问题只是关于如何彻底解决这个问题。一个正确方向的指针将不胜感激!

    非常感谢!

    5 个答案:

    答案 0 :(得分:2)

    另一个选择是保留Map个处理程序。如果您使用的是Java 8,它们甚至可以作为方法引用。

    // InputType and ResultType are types you define
    Map<String, Function<InputType, ResultType>> operations = new HashMap<>();
    operations.put("add", MathClass::add);
    // ...
    ResultType result = operations.get(userInput).apply(inputObject);
    

    这样做的一个缺点是所有操作的输入和输出类型必须相同。

    答案 1 :(得分:1)

    您可以为各种功能创建自定义注释。然后你可以使用你的数组想法,但让它使用反射来发现哪些函数有你的新注释以及它们的名称是什么。

    作为背景,请查看http://www.oracle.com/technetwork/articles/hunter-meta-2-098036.htmlhttp://www.oracle.com/technetwork/articles/hunter-meta-3-092019.html。他们有点老了,但似乎解决了必要的想法。

    答案 2 :(得分:0)

    如果您想要一个简短的解决方案,您可以随时使用反射。

    handle方法中,您可以执行以下操作:

    Method m = this.getClass().getMethod(functionName, new Class[]{});
    m.invoke(this, new Object[]{});
    

    答案 3 :(得分:0)

    假设您没有很多想要这样做的功能,并且不想让自己暴露于反射造成的安全风险,您可以使用字符串开关,如下所示:

    void handleFunction(String function) {
        switch (function) {
            case "foo":
                foo();
                break;
            case "bar":
                bar();
                break;
    
            default:
                throw new IllegalArgumentException("Unknown function " + function);
                break;
        }
    }
    

    启动Java 7,you can use Strings in a switch statement并且编译器会从中创建一些合理的东西

    答案 4 :(得分:0)

    我会做这样的事情:

    public class FunctionTest {
        private static final Map<String, Runnable> FUNCTIONS = new HashMap<String, Runnable>() {{
            put("add", () -> System.out.println("I'm adding something!"));
            put("div", () -> System.out.println("I'm dividing something!"));
        }};
    
        public void handle(String functionName) {
            if (!FUNCTIONS.containsKey(functionName)) {
                throw new IllegalArgumentException("No function with this name: " + functionName);
            }
            FUNCTIONS.get(functionName).run();
        }
    }
    

    您基本上可以使用任何功能界面代替Runnable,我使用它,因为它与您的add()方法匹配。您可以将函数的名称映射到它们的实际可执行实例,从Map按名称获取它们并执行它们。

    您还可以使用所需的可执行块创建enum

    public class FunctionsAsEnumsTest {
        private static enum MyFunction {
            ADD {
                @Override public void execute() {
                    System.out.println("I'm adding something");
                }
            },
            DIV {
                @Override public void execute() {
                    System.out.println("I'm dividing something");
                }
            };
    
            public abstract void execute();
        }
    
        public void handle(String functionName) {
            // #toUpperCase() might not be the best idea, 
            // you could name your enums as you would the methods.
            MyFunction fn = MyFunction.valueOf(functionName.toUpperCase());
            fn.execute();
        }
    }