簡體   English   中英

編寫此Java代碼的更好方法是什么?

[英]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來破解Swtingswitch 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粉絲:)

有關詳細信息,請查看本文以獲取有關IoC的簡要概述,然后查看本文以獲取文檔

暫無
暫無

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

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