Switch vs map for command prompt loop

Stefan Carlson :

I'm writing a program that runs as a repeating command prompt. The user starts the program, then is prompted to enter commands until the command exit is entered. The way it works is that each command is represented by a class that inherits from a CommandExecutor interface I created, which has an onCommand method that is called when that particular command is entered.

Currently, I have a HashMap<String, CommandExecutor> in my main class that stores all of the commands and their corresponding executors. When the program is launched, each command is registered into the map like so:

Map<String, CommandExecutor> executors = new HashMap<String, CommandExecutor>();

executors.put("help", new HelpCommand());
executors.put("list", new ListCommand());
executors.put("update", new UpdateCommand());
executors.put("wizard", new Wizard());
executors.put("build", new BuildCommand());
executors.put("new", new NewCommand());
executors.put("select", new SelectCommand());

With this design, the program loop looks like this:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
boolean cont;

while(cont) {
    // Reads line, parses input:
    // String lastCommand for command
    // String[] parameters for parameters

    if(lastCommand.equals("exit") {
        cont = false;
    } else {
        if(!executors.containsKey(lastCommand))
            System.out.println("Unknown Command!");
        executors.get(lastCommand).onCommand(lastCommand, parameters);
    }
}

Some code in the above snipets has been omitted for simplicity, as it is not relevant to this question.

Is this the most efficient way to go about something like this, or would it be better to simply use a switch statement kind of like this:

CommandExecutor exec;

switch(lastInput) {
case "exit":
    cont = false;
    break;
case "help"
    exec = new HelpCommand();
    break;
case "list";
    exec = new ListCommand();
    break;
case "update";
    exec = new UpdateCommand();
    break;
// etc
default:
    System.out.println("Unknown Command!");
}

exec.onCommand(lastInput, parameters);

This isn't so much an issue of getting the program to work. Rather, it as a question of which design is going to be better in terms of efficiency and performance, as well as which one is simply going to yield better written code.

SDJ :

Your original code is an application of the Command design pattern as described in the GoF book. It uses polymorphism.

In contrast, according to Martin Fowler (in the first edition of "Refactoring"), a switch statement like this is a "bad smell in code":

Most times you see a switch statement, you should consider polymorphism---Martin Fowler, Refactoring: Improving the Design of Existing Code, 2000.

The last edition of the book retreats a bit from the hard line, but still includes it in the list, albeit with the qualifier "repeated":

So we now focus on the repeated switch, where the same conditional switching logic (either in a switch/case statement or in a cascade of if/else statements) pops up in different places. The problem with such duplicate switches is that, whenever you add a clause, you have to find all the switches and update them. Against the dark forces of such repetition, polymorphism provides an elegant weapon for a more civilized codebase.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=163880&siteId=1