Contents
Command
From GoF Encapsulate a request as an object, thereby letting you
parameterise clients with different requests, queue or log requests, and
support undo and redo operations.
If there is a task which needs to be done, but who does that
task and in what way is not known at compile time, Command is a good pattern to
use.
When the Invoker class was created, its creator will have
given it an appropriate Concrete Command object. When the task needs to be done
at run-time, Invoker will call the Execute method passing appropriate
parameters.
There are many examples of this pattern in the .NET
Framework; one which springs to mind is reading or writing from a Stream. Most
classes which do this will take a Stream as a parameter; Stream is an abstract
class, with descendents like FileStream, TextStream, MemoryStream etc. These
are the concrete commands which read or write to different types of stream. See
for instance XmlTextWriter.
Commands can be
linked together via a �MacroCommand�. A MacroCommand is a Concrete Command (it
inherits from Command above), but its Execute method calls the Execute methods
of a number of other Concrete Commands which it contains.
Note the Receiver
object in the diagram. This is the object on which the Command is to do its
work. It can be set either as a parameter in the call to Execute, or by the
creator of the ConcreteCommand as a parameter to the constructor. In the latter
case, the creator would probably not be the class which actually calls Execute,
but another class which knows which type of Concrete Command is needed by the
Invoker. (The Invoker could be a non-specific object such as a MenuItem or
Button which only knows that when it is clicked it should call Execute on its
Command. This allows maximum reusability of the Invoker.)
Another common
diagram of Command is as follows:
This fleshes out the original GoF diagram by including
collaborations with the client which are implicit in the GoF text. Remember,
though, that these patterns do not exist as straight-jackets but inspirations.
Consequences:
- Decouples
the object invoking an operation from the object that knows how to do it
- Allows
a Client to vary the operations an invoker instigates without changing the
invoker
- Links
something which requires an action (the Invoker) with the object which can
carry it out (the Receiver) while avoiding coupling them together.
- The
Command can contain a wide range of intelligence. At one end of the range,
it passes on a call to the Receiver and does nothing else. At the other it
may do a very complex set of operations without having a receiver at all.
Notes from Vince Huston's excellent pages:
- Chain of Responsibility, Command,
Mediator, and Observer, address how you can decouple senders and
receivers, but with different trade-offs. Command normally specifies a
sender-receiver connection with a subclass.
- Chain of Responsibility can use Command
to represent requests as objects. [GOF, p349].
- Command and Memento act as magic tokens
to be passed around and invoked at a later time. In Command, the token
represents a request; in Memento, it represents the internal state of an
object at a particular time. Polymorphism is important to Command, but not
to Memento because its interface is so narrow that a memento can only be
passed as a value. [GOF, p346]
- Command can use Memento to maintain the
state required for an undo operation. [GOF, p242]
- MacroCommands can be implemented with
Composite. [GOF, p242]
- A Command that must be copied before
being placed on a history list acts as a Prototype. [GOF, p242]
- POSA's Command Processor pattern
describes the scaffolding Command needs to support full multilevel undo
and redo. [Vlissides, Java Report, Nov 2000, p80]
From CodePro Java Patterns
- Specify, queue, and execute requests at
different times. A Command object can have a lifetime independent of the
original request. If the receiver of a request can be represented in an
address space-independent way, then you can transfer a command object for
the request to a different process and fulfil the request there.
- support undo. The Command's Execute
operation can store state for reversing its effects in the command itself.
The Command interface must have an added Unexecute operation that reverses
the effects of a previous call to Execute. Executed commands are stored in
a history list. Unlimited-level undo and redo is achieved by traversing
this list backwards and forwards calling Unexecute and Execute,
respectively.
- support logging changes so that they
can be reapplied in case of a system crash. By augmenting the Command
interface with load and store operations, you can keep a persistent log of
changes. Recovering from a crash involves reloading logged commands from
disk and re-executing them with the Execute operation.
- structure a system around high-level
operations built on primitives operations. Such a structure is common in
information systems that support transactions. A transaction
encapsulates a set of changes to data. The Command pattern offers a way to
model transactions. Commands have a common interface, letting you invoke
all transactions the same way. The pattern also makes it easy to extend
the system with new transactions.