Command Oriented Interface
23 November 2003
The most common style of interface to a module is to use procedures, or object methods. So if you want a module to calculate a bunch of charges for a contract, you might have a BillingService class with a method for doing the calculation, calling it like this
aBillingService.calculateCharges(aContract)
A command oriented interface would have a command class for each operation, and be called with something like this
CalculateChargeCommand.new(aContract).run()
Essentially you have one command class for each method that you would have in the method-oriented interface.
A common variation is to have a separate command executor object that actually does the running of the command.
aCommandExecutor.run(CalculateChargeCommand.new(aContract))
If you've used frameworks like Struts, you'll recognize that the action classes follow this style of operation.
So why do people like and dislike this approach? First off it's fair to say that a command oriented interface is rather more involved than a method oriented one. You have instantiate the command and pass them through for execution. This is more involved than just calling a method, which is why even fans of this approach only use them for significant interfaces (service layers, server-side logic, interfaces of major subsystems).
Command oriented interfaces have a number of benefits. One of the primary ones is the ability to easily add common behavior to commands by decorating the command executor. This is very handy for handling transactions, logging, and the like. Commands can be queued for later execution and (if the commands and their data are serializable) be passed across a network. Command results can be cached by holding results against a key synthesized from the command name and arguments.
Where I've seen complaints about commands, the biggest issue is due to a lot of duplicated logic in commands. This tends to happen most when the commands are Transaction Scripts that contain a lot of logic. This isn't necessarily an issue with using commands as opposed to methods; this problem is a general issue with Transaction Scripts. It may that command-oriented structure tends to exaggerate this, if only because many people feel that a class needs a page or two of code to be worthwhile, and thus end up putting more code in the command than should be there.
You'll notice I've used the word interface for this page. This reflects that the choice about using commands is primarily about the interface to clients rather than about the actual implementation of the command logic. It's perfectly reasonable to have command classes whose run method is just a single line calling out to another method. Doing this gives you all the advantages of commands, but allows you to keep the logic out of the command classes themselves. Such command classes have very few lines of code.
A common question with commands is what to return. Generic run methods need a general return type, such as Object or CommandResult, but you'll want a more specific type to get the results from running a command. One route is to define a result class for each command class and use a naming convention, so that CalculateChargeCommand would have a return type of CalculateChargeResult. Another route is to make the command store the results in the same object. In this case you would first run the the command, and then interrogate the command object for results.