2009-10-19 44 views
2
public void handleParsedCommand(String[] commandArr) { 
    if(commandArr[0].equalsIgnoreCase("message")) { 
     int target = Integer.parseInt(commandArr[1]); 
     String message = commandArr[2]; 
     MachatServer.sendMessage(target, this.conId, message); 
    } else if(commandArr[0].equalsIgnoreCase("quit")) { 
     // Tell the server to disconnect us. 
     MachatServer.disconnect(conId); 
    } else if(commandArr[0].equalsIgnoreCase("confirmconnect")) { 
     // Blah blah and so on for another 10 types of command 
    } else { 
     try { 
      out.write("Unknown: " + commandArr[0] + "\n"); 
     } catch (IOException e) { 
      System.out.println("Failed output warning of unknown command."); 
     } 
    } 
} 

我有這部分服務器代碼來處理消息的類型。每條消息包含commandArr[0]中的類型和commandArr[]其餘部分中的參數。但是,這個當前的代碼在工作時似乎很不起眼。有更好的方法來處理它嗎? (據我所知,String值不能在switch語句中使用,即使這樣,一個switch聲明只會是一個小的提升。寫這個Java代碼的更好方法是什麼?

+0

的Java的什麼版本? SWITCH是*最後*在最新的(或已經發布了嗎?)版本中支持字符串.. – 2009-10-19 17:45:26

+0

它是Java 6。 。 – Macha 2009-10-19 17:48:19

+0

也許http://stackoverflow.com/questions/1199646/long-list-of-if-statements-in-java/1199677與此相關? – dfa 2009-10-19 18:31:15

回答

8

我該使用Command Design Pattern

重構基本上,你的每一個命令,信息,退出,confirmconnect和默認將有一個類實現和將執行命令接口。

/*the Command interface*/ 
public interface ICommand { 
    void execute(String[] commandArr); 
} 

public class Message implements ICommand { 
    void execute(String[] commandArr) { 
     int target = Integer.parseInt(commandArr[1]); 
     String message = commandArr[2]; 
     MachatServer.sendMessage(target, this.conId, message); 
    } 
} 

//same type of class for other commands 

public class CommandManager { 
    public ICommand getCommand(String commandName) { 
     //store all the commands in a hashtable. 
     //Pull them out by name as requested. 
    } 

    //Esko's suggestion from comments 
    public static void executeImmediately(String[] commandArr) { 
     getCommand(commandArr[0]).execute(commandArr); 
    } 
} 


public void handleParsedCommand(String[] commandArr) { 

    ICommand command = CommandManager.getCommand(commandArr[0]); 
    command.execute(commandArr); 

//or Esko 

    CommandManager.executeImmediately(commandArr); 

} 
+0

我不知道你是不是在描述戰略模式而不是命令模式? – 2009-10-19 17:47:50

+0

策略需要能夠相互替代;他們是做同樣事情的替代方法。我認爲這不符合戰略模式的應用。 – jprete 2009-10-19 17:50:09

+2

策略描述可插入算法。例如排序,你可以有一個QuickSortStrategy或BubbleSortStrategy。兩者的最終結果都是一樣的,一個有序列表。但它如何完​​成是不同的。命令封裝了一個動作。 – Bob 2009-10-19 17:58:23

1

看看Commons CLI這是一個命令行參數解析器。

這是它的用法some examples

+0

它們不是命令行參數。他們來自網絡。 – Macha 2009-10-19 17:46:58

+0

源並不重要,真的。 CLI採用'String []'作爲輸入。 – ChssPly76 2009-10-19 17:50:49

1

對於初學者來說,我會做的指令和執行每個命令的類型(比如實現已知接口的匿名類),然後檢索從右側類的類之間的映射地圖,然後傳遞其餘的參數。

如果有意義,你可以在這裏用一個靜態方法來檢索正確的枚舉,這樣你就可以在需要時切換(比如你必須在10箇中的5個上做同樣的事情)命令)。

0

首先,您每次都讀取數組中相同的元素。這應該是首先要考慮的因素。 equalsIgnoreCase有點長,所以首先要規範大小寫(不要選擇默認語言環境!)。

可以使用enum s破解Swting s的switch s。 JDK7可能在String,IIRC上包含switch

0

我喜歡Bob的回答。另一種方法是使用Spring框架和IoC功能。基本上,我之前使用過Spring(xml中的膨脹)來創建Map,其中每個命令對象都使用一個鍵存儲。關鍵將與commandArr[0]中的文字相同。

所以你的XML看起來像

<property name="commands"> 
    <map> 
    <entry> 
     <key> 
      <value>message</value> 
     </key> 
     <ref bean="messageCommand" /> 
    </entry> 
    </map> 
</property> 
<bean id="messageCommand" ref="org.yourorg.yourproject.MessageCommand" /> 

然後在你的代碼...

commands.get(commandArr[0]).execute() //or whatever 

這可以讓你不運行任何類型的初始化代碼。你所要做的就是膨脹xml。 Spring會爲你填充地圖。此外,您可以使用類似的語法在類中定義任何必需的數據成員。另外,如果你需要添加功能,你所要做的就是改變xml,而不是用代碼重新編譯。我個人對於國際奧委會的概要的huuuuge風扇:)

欲瞭解更多信息,請this article,然後檢查了this article for the documentation

6

這裏有兩個變種使用枚舉在(幾乎)提供相同的行爲一個更可讀的方式:

1)枚舉的類型安全開關:

enum CommandType { 
MESSAGE, 
QUIT, 
CONFIRMCONNECT 
} 

public void handleParsedCommand(String[] commandArr) { 
    CommandType cmd = null; 

    try { 
     cmd = CommandType.valueOf(commandArr[0].toUpperCase()); 
    } catch (IllegalArgumentException e) { 
     // this kind of error handling, seems a bit strange, by the way. 
     try { 
      out.write("Unknown: " + commandArr[0] + "\n"); 
     } catch (IOException e) { 
      System.out.println("Failed output warning of unknown command."); 
     } 
     return; 
    } 
    switch(cmd) { 
     case MESSAGE: 
      int target = Integer.parseInt(commandArr[1]); 
      String message = commandArr[2]; 
      MachatServer.sendMessage(target, this.conId, message); 
     case QUIT: 
      // Tell the server to disconnect us. 
      MachatServer.disconnect(conId); 
     case CONFIRMCONNECT: 
      // Blah blah and so on for another 10 types of command 
     } 
    } 
} 

主要好處是,代碼更易讀,但你avoi d爲每種情況創建新的方法或類,如果處理代碼只有一行或兩行,則不允許你想要的。

2)另一種基於枚舉變,這實際上是一個Command模式,但太大的膨脹代碼:

enum CommandType { 
    MESSAGE { 
     void execute(CommandProcessor cp, String[] params) { 
      int target = Integer.parseInt(params[1]); 
      String message = params[2]; 
      MachatServer.sendMessage(target, cp.conId, message);   
     } 
    }, 
    QUIT { 
     void execute(CommandProcessor cp, params param) { 
      MachatServer.disconnect(cp.conId); 
     } 
    }, 
    CONFIRMCONNECT { 
     void execute(CommandProcessor cp, params param) { 
       // Blah blah and so on for another 10 types of command 
     } 
    }; 

    abstract void execute(CommandProcessor cp, String[] param); 
} 
public void handleParsedCommand(String[] commandArr) { 
    CommandType cmd = null; 

    try { 
     cmd = CommandType.valueOf(commandArr[0].toUpperCase()); 
    } catch (IllegalArgumentException e) { 
     try { 
      out.write("Unknown: " + commandArr[0] + "\n"); 
     } catch (IOException e) { 
      System.out.println("Failed output warning of unknown command."); 
     } 
     return; 
    } 
    cmd.execute(this, commandArr); 
} 
2

葉氏,看起來像一個Command + Prototype模式給我。

在命令中你定義了要做什麼,原型是將每個命令的一個實例放在一個查找表中,並「克隆」它們以便每次執行。

的重構將是這樣的:

前:

public void handleParsedCommand(String[] commandArr) { 
     if(commandArr[0].equalsIgnoreCase("message")) { 
     int target = Integer.parseInt(commandArr[1]); 
     String message = commandArr[2]; 
     MachatServer.sendMessage(target, this.conId, message); 
    } else if(commandArr[0].equalsIgnoreCase("quit")) { 
     // Tell the server to disconnect us. 
     MachatServer.disconnect(conId); 
    } else if(commandArr[0].equalsIgnoreCase("confirmconnect")) { 
     // Blah blah and so on for another 10 types of command 
    } else { 
     try { 
      out.write("Unknown: " + commandArr[0] + "\n"); 
     } catch (IOException e) { 
      System.out.println("Failed output warning of unknown command."); 
     } 
    } 
} 

後:

public void handleParsedCommand(String[] commandArr) { 
    Command.getCommand(commandArr).execute(); 
} 


// Define the command and a lookup table 
abstract class Command { 

    // Factory using prototype 
    public static Command getCommand(String [] commandArr) { 
     // find the handling command 
     Command commandPrototype = commandMap.get(commandArr[0]); 
     // if none was found, then use "uknown" 
     if (commandPrototype == null) { 
      commandPrototype = commandMap.get("unknown"); 
     } 
     // Create an instance using clone 
     Command instance = commandPrototype.clone(); 
     instance.args = commanrArr; 
     return instance; 

    } 

    // lookup table (switch substitute) 
    private static Map<String,Command> commandsMap = new HashMap()<String,Command>(){{ 
      put("message"  , new MessagCommand()); 
      put("quit"   , new QuitCommand()); 
      put("confirmconnect", new ConfirmConnectCommand()); 
      ... 
      put("unknow"  , new UnknownCommand()); 

    }}; 


    // args of the command 
    private String [] args; 


    public void execute(); 

    String [] getArgs(){ 
     return this.args; 
    } 


} 

而且提供的具體實現

class MessageCommand extends Command { 
    public void execute(){ 
     int target = Integer.parseInt(commandArr[1]); 
     String message = commandArr[2]; 
     MachatServer.sendMessage(target, this.conId, message); 
    } 
} 

class MessageCommand extends Command { 
    public void execute(){ 
     int target = Integer.parseInt(getArgs()[1]); 
     String message = getArgs()[2]; 
     MachatServer.sendMessage(target, this.conId, message); 
    } 
} 

class QuitCommand extends Command { 
    public void execute() { 
     MachatServer.disconnect(conId); 
    } 
} 

class ConfirmConnectCommand extends Command { 
    public void execute() { 
    /// blah blah blah 
    } 
} 
class UnknowCommand extends Command { 
    public void execute() { 
     try { 
      out.write("Unknown: " + commandArr[0] + "\n"); 
     } catch (IOException e) { 
      System.out.println("Failed output warning of unknown command."); 
     } 
    } 
} 

// ... other 10 implementations here... 
相關問題