Command Pattern

(from Design Patterns and PLoP'95)

Synopsis

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Context

You want to model the time evolution of a program:

In other words, you want a kind of Reflection where what is being described is work flow, not just instantaneous data.

Forces

Solution

Explicitly represent units of work as Command objects. Units of work depend on the application and may range from reading and writing individual variables to reformatting a text document. The interface of a Command object can be as simple as a DoIt() method. Extra methods can be used to support undo and redo. Commands can be persistent and globally accessible, just like normal objects.

Commands are parameterized by the variable to be written, word to delete, place to move a figure to, etc. These parameters should be abstract, to avoid embedded references which would hinder logging and communicating a Command. For example, variables should be referred to by name, not pointer, and words should be referred to by position in the text.

For the Command to perform its own undo, it needs to store information destroyed by the operation. For example, the old value of the variable, the contents of the word being deleted, and the old position of the figure. The UndoIt() method can use this to back out of the operation. For safety, the Command could also store whether it has been done or not.

Commands are sent to a Command Processor which may queue, prioritize, and distribute them among machines or threads. The Command Processor can take care of logging the Commands for future undo. It can also schedule a Command to occur at a particular time or under specific conditions.

When all Commands are logged, storing the program state is redundant, because the program state at any moment in time can be reconstructed by replaying the log up to that point. Thus program state is essentially a cache of the computation stored the log. This offers a simple way to implement undo: blow away the current state and reconstruct the state at a previous time. To speed up this operation, the state can be periodically written, or checkpointed, to the log. State can then be reconstructed by starting with the last checkpoint and replaying the Commands since then.

Consequences

Implementation

See Design Patterns for sample code.

Known Uses


Thomas Minka
Last modified: Fri Sep 02 15:19:03 GMT 2005