1

I have a collection of objects using the command design pattern, ie they implement an abstract Command class and have an execute() method.

When called (for example) from the command line, you could do something like this, but its seriously clunky, how would you implement this:

public void main(String[] arg) {
    Command c = null;

    if(arg[0].equals("FirstCommand") {
        c = new FirstCommand(arg[1]);
    }
    if(arg[0].equals("SecondCommand") {
        c = new SecondCommand(arg[1], arg[2]);
    }
    if(arg[0].equals("ThirdCommand") {
        c = new ThirdCommand(arg[1], Long.parseLong(arg[2]));
    }
    //.....etc....
    c.execute();
}

Obviously as the list of available commands grows, this becomes quite tedious code

2 Answers 2

1

Reflection is easy. Start with this:

final Class[] argTypes = new Class[args.length - 1];
final String[] cmdArgs = new String[args.length - 1];
for (int i = 0; i < argTypes.length; i++) {
  argTypes[i] = String.class;
  cmdArgs[i] = args[i+1];
}
final Command c = (Command) Class.forName(MY_PACKAGE + args[0]).getConstructor(argTypes)
   .newInstance(cmdArgs);

Now, the only thing to fix is that you are going to have to push parsing and validation into your Command constructors. Or, if you want to get fancy, you can find a constructor based on arg count only, see what arg types it accepts, and parse the cmdline args appropriately.

Sign up to request clarification or add additional context in comments.

Comments

0

A generic solution that does not require you to keep track of available commands would be to use reflection for instantiation of the commands. You would either have a constructor taking a list of parameters or you define the execute method like McDowell suggested. That depends if you want to re-execute the same command multiple times with the same arguments and whether commands could benefit from cached results (stateless vs. stateful).

The command name would be the simple name of the class. you would only add the package to create a fully qualified name and then class.getConstructor(Class[] params) and invoke that constructor (or use the default constructor if you choose to pass parameters to the execute method).

2 Comments

It is my understanding that its not possible to do this without some complex class path loading hackery?
what do you mean by classpath hackery? my answer assumes that the classes specified as parameters are available to the classloader of the running class. Marko TopoInik posted the code that I was too lazy to write for the answer