2014-07-26 60 views
0

我正在嘗試開發Java中的解析器。這是一個遊戲,將通過標準輸入和輸出與解析器進行通信。我正在嘗試創建解析器,使其可擴展性強,易於使用。何時使用Java Reflection API,何時不使用

目標是在服務器上運行可定製的「腳本」。解析器將跟蹤服務器發送的所有內容,並且可以在必要時進行響應。

這意味着我將不得不將許多命令從服務器映射到解析器中的不同事件。在PHP中,我知道你可以很容易地調用一個變量函數,這在Java中沒有使用Reflection API似乎是不可能的。

讓我從輸入到解析器的示例開始。 GAME_TIME 10將被髮送到解析器以將遊戲計時器的當前狀態更新爲10.

我計劃創建一個處理基本服務器事件的庫,例如當前有多少玩家在線。該庫的目標是使服務器管理員更輕鬆地爲這些定製服務器編寫腳本。

現在,當我首先處理這個問題時,我想到了創建一個HashMap<String, String[]>,它將命令的名稱映射到參數類型的數組。例如, map.put("GAME_TIME", new String[]{"time:int"});由此產生的問題是,以某種形式接收命令後,如何處理數據?我想出了

一種解決方案是簡單地有一個大的switch語句,將匹配的命令,然後從那裏調用一個方法,但呈現在地圖上沒有意義的,將是一個很大混亂。

我知道有一種方法可以使用反射從名稱中調用方法,但我不確定這是否是一個適當的解決方案,它肯定會看起來更漂亮,並使代碼更短(除非我缺少東西)。

任何幫助,將不勝感激。

這裏是我現在有(和不喜歡)的開關方法。

public class Parser { 

    public List<ServerEventReceiver> receivers = new ArrayList<>(); 

    public void addReceiver(ServerEventReceiver ser) { 
     receivers.add(ser); 
    } 

    public void removeReceiver(ServerEventReceiver ser) { 
     receivers.remove(ser); 
    } 

    public void parse(String command, String... args) { 
     switch(command) { 
      case "GAME_TIME": 
       /** 
       * Allow any number of receivers to listen to the game_time event 
       */ 
       for(ServerEventReceiver ser: receivers) 
        ser.game_time(args[0]); 
       break; 
     } 
    } 

} 

的總體目標是允許自定義腳本來實現了很多的服務器事件的方法(空),使他們能夠覆蓋其中的任何他們想從接收數據的一些類。

+0

不能使用switch語句處理字符串。 – chrylis

+2

你可以在Java 7 – Tristan

+0

呵呵。顯然它可以和編譯時常量一起工作。無論如何,開關很少是最好的答案。查找替換條件與多態性,這基本上是我的答案建議。 – chrylis

回答

2

我的建議是用nameexecute方法將命令抽象成一個類,然後保留一個Map<String, Command>,讓你按名稱查找對象。這促進了模塊化(每個類都有一件事)和可擴展性(只需添加更多的類)。

+0

這是否意味着每個命令都會有一整個班級? – Tristan

+1

類非常輕量級。事實上,對類的引用佔用與對字符串引用一樣多的內存。在這一天結束時,這個解決方案可能會佔用更少的內存。這並不重要 - 可讀的乾淨代碼總是傾向於輕微或想象的性能增益。 – vidstige

+0

但是如果正確完成,反射是不是很可讀?這肯定會減少所需的代碼量。 – Tristan

0

看起來好像這將是一個很好的用例Lambda表達式(1.8)。

Map<String,Consumer<String[]>> c2f = new HashMap<>(); 
Consumer<String[]> printer = (strings) -> { 
    System.out.println("string:" + strings[0]); 
}; 
c2f.put("print", printer); 

以及調用:

String command = ...;; 
String[] data = ...; 
c2f.get(command).accept(data); 

它非常強大,你可以用泛型結合起來......

節拍反映,因爲它是類型安全的。