2014-07-26 16 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); 

它非常强大,你可以用泛型结合起来......

节拍反映,因为它是类型安全的。