Diagram of the command pattern
The Command pattern is used to associate an object with an operation that is deferred to at later time for execution. The command itself is an object that contains the target of the command (known as the receiver) along with the operation to perform on the target. This means the command object can be treated like any other object, even putting it into a list.
A common application for the Command pattern is an undo buffer. Another application is a batch processor.
At its heart, a Command object takes two parameters: The object to work on and an operation to use. The operation is typically a function pointer (in C++) or a delegate (in C#). A Command object can hold additional parameters if the associated operation requires additional parameters.
When invoked, the Command object calls the operation with the receiver object and whatever additional parameters that might be required. The invocation is typically a single method called execute()
so all Command objects look the same to the entity doing the invocation of the Commands.
It is typical for the Command objects to be created by one entity and passed to another entity for invocation.
How to Use
For example, a program that supports undo would work like this (this is a simplistic undo):
- Define all operations as functions that takes a single receiver (of the command) to operate on, along with any necessary additional parameters.
- Any time an operation other than Undo is invoked by the user:
- Create a Command object with the function for that operation along with the receiver on which the function applies
- Store the Command object in the undo container
- Invoke the Command object just created
- Repeat step 2 until the user selects Undo.
- Perform the Undo:
- If there are any commands to undo then
- Completely reset the receiver that all commands are applied to
- Remove the last Command object from the undo container, if any
- For all Command objects in the undo container, invoke each Command in order (oldest to newest) on the receiver. This puts the receiver back into the state it was in before the last command was applied.
This example implements the above algorithm. A Command_TextObject instance represents the target of the commands. The commands themselves are stored in a Command instance. A simple stack is used to remember the commands in the order in which they are applied. After several commands are applied, the commands are undone in reverse order.
Note: In C++, a std::vector<> is used instead of a std::stack<> because there is no way to iterate over the contents of a stack.
C++
void Command_Exercise()
{
std::cout << std::endl;
std::cout << "Command Exercise" << std::endl;
Command_TextObject::shared_ptr_t text = std::make_shared<Command_TextObject>("This is a line of text on which to experiment.");
std::cout << " Now perform undo until back to original" << std::endl;
std::cout << " Done." << std::endl;
}
static void Command_ApplyReplaceCommand(Command_TextObject *text, const char *searchPattern, const char *replaceText)
Helper function to create a Command object that replaces text in the given Command_TextObject,...
static void Command_ApplyReverseCommand(Command_TextObject *text)
Helper function to create a Command object that reverses the order of the characters in the given Com...
static void Command_Undo(Command_TextObject *text)
Perform an undo on the given Command_TextObject, using the commands in the "global" undo list....
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....
C#
public void Run()
{
Console.WriteLine();
Console.WriteLine("Command Exercise");
Console.WriteLine(" Starting text: \"{0}\"", text);
Console.WriteLine(" Now perform undo until back to original");
Console.WriteLine(" Final text : \"{0}\"", text);
Console.WriteLine(" Done.");
}
static StackEntry * _commandUndoList
The stack used to remember the commands for undo.
Container for a string. Need to use a structure to keep the starting text and the current text togeth...
Python
def Command_Exercise():
print()
print("Command Exercise")
print(" Starting text: \"{0}\"".format(text.ToString()))
print(" Now perform undo until back to original")
print(" Final text : \"{0}\"".format(text.ToString()))
print(" Done.")
C
void Command_Exercise(void)
{
printf("\nCommand_Exercise\n");
{
printf(" Now perform undo until back to original\n");
}
printf(" Done.\n");
}
const char * Command_TextObject_ToString(Command_TextObject *textObject)
Converts the Command_TextObject to a string (basically, returns the current text from the Command_Tex...
void Command_TextObject_Clear(Command_TextObject *textObject)
Clear the contents of the specified Command_TextObject, releasing any allocated resources associated ...
bool Command_TextObject_Initialize(Command_TextObject *textObject, const char *startingText)
Initialize a Command_TextObject with the specified text.
Rust
(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)
pub fn command_exercise() -> Result<(), String> {
println!("");
println!("Command Exercise");
// Note: The context's undo list owns the commands. When an undo operation
// is done, the command is removed from the list and goes away at the end
// of the undo function.
let mut command_context = CommandContext::new();
let mut text_object = CommandTextObject::new("This is a line of text on which to experiment.");
println!(" Starting text: \"{text_object}\"");
command_context.apply_replace_command(&mut text_object, "text", "painting");
command_context.apply_replace_command(&mut text_object, "on", "off");
command_context.apply_reverse_command(&mut text_object);
command_context.apply_replace_command(&mut text_object, "i", "!");
println!(" Now perform undo until back to original");
command_context.undo(&mut text_object);
command_context.undo(&mut text_object);
command_context.undo(&mut text_object);
command_context.undo(&mut text_object);
println!(" Final text : \"{text_object}\"");
println!(" Done.");
Ok(())
}
See Also