簡體   English   中英

字符串輸入,指定要調用的函數[Java] [最佳實踐]

[英]String input to specify which function to call [Java] [Best Practice]

應用程序

我正在編寫一個根據用戶輸入執行某些功能的應用程序。 例如,如果用戶輸入為“ 1 2 add”,則輸出為“ 3”。 我旨在實現許多這樣的方法(div,取模等)。 當我的掃描儀識別出“ add”之類的函數名稱時,應調用“ 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()
  • 執行()
  • 然后如果用戶輸入命令匹配的getName我可以創建在一個FunctionHandler 函數的陣列(手動地),通過它,我可以循環看()。 但是,為每個函數使用不同的類也不是一件容易的事,而且也不能解決我要添加的每個函數必須在兩個地方做的問題:類和數組。

    這個問題只是關於找出如何徹底解決此問題的方法。 朝着正確方向的指針將不勝感激!

    非常感謝!

    另一種選擇是保留處理程序的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);
    

    這樣做的缺點是,所有操作的輸入和輸出類型必須相同。

    您可以為各種功能創建自定義注釋。 然后,您可以采用數組的想法,但是可以使用反射來發現哪些函數具有新的注釋以及它們的名稱是什么。

    作為背景,請訪問http://www.oracle.com/technetwork/articles/hunter-meta-2-098036.htmlhttp://www.oracle.com/technetwork/articles/hunter-meta-3 -092019.html 他們有些老,但是似乎解決了必要的想法。

    如果您需要一個簡短的解決方案,則可以始終使用反射。

    在您的handle方法中,您可以執行以下操作:

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

    假設您沒有很多這樣的功能,並且不想暴露於反射所帶來的安全風險,則可以使用字符串開關,如下所示:

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

    從Java 7開始, 您可以在switch語句中使用Strings,編譯器將從中做出合理的選擇

    我會做這樣的事情:

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

    暫無
    暫無

    聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

     
    粵ICP備18138465號  © 2020-2024 STACKOOM.COM