[英]Better way to write this Java code?
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
語句也只是一個很小的改進。
我會使用Command Design Pattern重構它。
基本上,您的每個命令,消息,退出,確認連接和默認都將具有類實現,並將實現命令接口。
/*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);
}
以下是兩個使用枚舉的變體(幾乎)以更易讀的方式提供相同的行為:
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
}
}
}
主要的好處是代碼更具可讀性,但是您避免為每種情況創建新的方法或類,如果處理代碼只有一行或兩行,則不允許創建新的方法或類。
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);
}
是的,看起來像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...
看一下Commons CLI ,它是一個命令行參數解析器。
以下是一些使用示例 。
你可以使用枚舉
對於初學者,我會在命令和執行每種類型命令的類(比如實現已知接口的匿名類)之間創建一個映射,然后從映射中檢索正確的類,然后將其余的參數傳遞給它。
如果它有意義,你可以使用靜態方法在這里使用枚舉來檢索正確的方法,這樣你就可以在需要時切換(比如你必須在10個命令中的5個上做同樣的事情)。
首先,您每次都在讀取數組的相同元素。 這應該是首先要考慮的因素。 equalsIgnoreCase
有點長,所以首先規范化大小寫(不要選擇默認的語言環境!)。
可以使用enum
來破解Swting
的switch
。 JDK7可能包括String
,IIRC上的switch
。
我喜歡鮑勃的回答。 另一種方法是使用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粉絲:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.