Monday, December 04, 2006

The Command Pattern

The Command pattern is probably the most used design pattern. In command pattern, objects are used to represent actions. This allows you to issue requests to objects without knowing anything about the operation being
requested or the receiver of the request. The command object can act as an interface between the client and the reciever. In Design Patterns, the authors define the Command pattern as:
Encapsulate a request as an object,
thereby letting you parameterize clients with different requests,queue or log requests, and support undoable operations.
Note that, the undoable is actually undo-able and not un-doable. Using the command pattern helps you to :
  • Decouple the object that invokes the operation from the one that performs the action.
    described earlier.
  • Assemble commands into a composite command. An example is the MacroCommand class. Composite commands are an instance of the Composite pattern.
  • Add new Commands, without having to change existing classes.
The following is a list of scenarios where the command pattern may be put to use.
  • Improve API design: In some cases, code that uses a command object is shorter, clearer, and more declarative than code that uses a procedure with many parameters. This is particularly true if a caller typically uses only a handful of the parameters and is willing to accept sensible defaults for the rest.
  • A command object is a temporary storage for procedure parameters. It can be used while assembling the parameters for a function call and allows the command to be set aside for later use.
  • A class is a convenient place to collect code and data related to a command. A command object can hold information about the command, such as its name or which user launched it; and answer questions about it, such as how long it will likely take.
  • Treating commands as objects enables data structures containing multiple commands (Macro commands).
  • Multi-level undo: The Command's Execute operation can store state for reversing its effects in the command itself, there by allowing you implement the undo action. By storing the the list of commands executed seperately, multi-level undo can be achieved.
  • Transactional behaviorUndo is perhaps even more essential when it's called rollback and happens automatically when an operation fails partway through. Installers need this. So do databases. Command objects can also be used to implement two-phase commit.
  • Progress barsSuppose a program has a sequence of commands that it executes in order. If each command object has a getEstimatedDuration() method, the program can easily estimate the total duration. It can show a progress bar that meaningfully reflects how close the program is to completing all the tasks.
  • GUI buttons and menu items: In Swing programming, an Action is a command object. In addition to the ability to perform the desired command, an Action may have an associated icon, keyboard shortcut, tooltip text, and so on.
  • Queuing Requests: A typical, general-purpose thread pool class might have a public addTask() method that adds a work item to an internal queue of tasks waiting to be done. It maintains a pool of threads that execute commands from the queue. The items in the queue are command objects.
  • Logging Requests: If all user actions are represented by command objects, a program can log a sequence of actions by keeping a list of the command objects that are executed. In case of a system failure, the program can execute the same sequence of events.
  • Wizards: Often a wizard presents several pages of configuration for a single action that happens only when the user clicks the "Finish" button on the last page. In these cases, a natural way to separate user interface code from application code is to implement the wizard using a command object. The command object is created when the wizard is first displayed. Each wizard page stores its GUI changes in the command object, so the object is populated as the user progresses. "Finish" simply triggers a call to execute(). This can be seen as a special case of Queuing requests.
  • Networking: It is possible to send whole command objects across the network to be executed on the other machines, for example player actions in computer games.

2 comments: