Design Patterns
4. It's easy to add new Commands, because you don't have to change existing classes.
Implementation
Consider the following issues when implementing the Command pattern:
1. How intelligent should a command be? A command can have a wide range of abilities. At one extreme
it merely defines a binding between a receiver and the actions that carry out the request. At the other
extreme it implements everything itself without delegating to a receiver at all. The latter extreme is
useful when you want to define commands that are independent of existing classes, when no suitable
receiver exists, or when a command knows its receiver implicitly. For example, a command that creates
another application window may be just as capable of creating the window as any other object.
Somewhere in between these extremes are commands that have enough knowledge to find their receiver
dynamically.
2. Supporting undo and redo. Commands can support undo and redo capabilities if they provide a way to
reverse their execution (e.g., an Unexecute or Undo operation). A ConcreteCommand class might need
to store additional state to do so. This state can include
o the Receiver object, which actually carries out operations in response to the request,
o the arguments to the operation performed on the receiver, and
o any original values in the receiver that can change as a result of handling the request. The
receiver must provide operations that let the command return the receiver to its prior state.
To support one level of undo, an application needs to store only the command that was executed last.
For multiple-level undo and redo, the application needs a history list of commands that have been
executed, where the maximum length of the list determines the number of undo/redo levels. The history
list stores sequences of commands that have been executed. Traversing backward through the list and
reverse-executing commands cancels their effect; traversing forward and executing commands
reexecutes them.
An undoable command might have to be copied before it can be placed on the history list. That's
because the command object that carried out the original request, say, from a MenuItem, will perform
other requests at later times. Copying is required to distinguish different invocations of the same
command if its state can vary across invocations.
For example, a DeleteCommand that deletes selected objects must store different sets of objects each
time it's executed. Therefore the DeleteCommand object must be copied following execution, and the
copy is placed on the history list. If the command's state never changes on execution, then copying is not
required—only a reference to the command need be placed on the history list. Commands that must be
copied before being placed on the history list act as prototypes (see Prototype (91)).
Pag