Summary
Pattern Name | Command Pattern |
Pattern Type | Behavioral Pattern |
Scope | Object |
Other Names | Action Transaction |
Tagline | Wrap request in an object |
Use cases | 1. When we want to create an object to store a command/request. 2. When we want to support features like undo or central logging of commands. |
Related Patterns | Composite Memento |
Difficulty Level | Medium |
Implementations |
Definition
Command pattern wraps a request/command in an object. Then we can pass the object anywhere and later when we want to execute the command the object can be used.
As the request is wrapped in an object, the execution of the command is completely separate from the request-sending part. Also, the Command pattern can be used to support features like undoing and logging commands.
The state of the command object is wrapped with the command, which makes execution and undoing (and redoing) of the command possible. The logging of commands enables system recovery in case of a system crash.
Command pattern enables adding a new command very easy, as new command can be added without any change in existing code.
The client can issue any of the commands, without any knowledge of the command details or the receiver of the command. The lifetime of a command object can be independent of the sent request.
Use Cases
Here are a few uses of the Command pattern-
- When we want to store a command/request in an object.
- When we want to separate request/command sending and execution process.
- When we want to support the undoing and/or redoing commands.
- When we want log commands, to support system recovery in case of a crash.
- When we want to add new commands without any change in existing code.
- When we want to queue requests/commands and execute those at different times.
Implementation
Command pattern has 3 elements involved in the implementation.
- Command Interface: an interface(or abstract class) to ensure the common interface for all command classes.
- Concrete Command Classes: classes that implement the command interface and are responsible for executing command.
- Command Controller: class to take the command as param and executed the command. This controller can also contain additional functionality.
Take a look at the following diagram to understand the implementation of Command pattern.
Follow the steps below to implement Command pattern:
- Create an interface to ensure a common interface for all command classes.
- Create command classes and implement command interface.
- Create a command controller class. In this class create functions that take the command object as a param and execute functions/commands from that command object. This class can contain additional functions if required by the client.
- In the client create objects of command and pass that to the controller class functions for execution.
Examples
Example #1: Simple Command Pattern
Command [Interface and Concrete Command Classes]
// Command interface
interface CommandI
execute()
undo()
end interface
// First command class
class Command1 implements CommandI
method execute()
output "Command1: Executing"
end method
method undo()
output "Command1: Undoing"
end method
end class
// Second command class
class Command2 implements CommandI
var prop1: String
constructor(prop1Param: string) {
prop1 = prop1Param
}
method execute()
output "Command2: executing -- Prop1 value: " + prop1
end method
method undo()
output "Command2: undoing"
end method
end class
Controller
// Command controller
class CommandControl
var commandList: CommandI[] = []
method execute(command: CommandI)
// Call the command execution method
command.execute()
// Add command to list to keep track of the command
commandList.add(command)
end method
method remove(command: CommandI)
// Call the undoing process of the command
command.undo()
// Find the command and remove command from list
cocmmandList.remove(command)
end method
// Undo the last executed command
method undo()
// Find the last element
var lastElementIndex = commandList.size() - 1
var lastCommand = commandList.get(lastElementIndex)
// Remove command
commandList.remove(lastCommand)
end method
end class
Demo
// Demo
var commandControl = new CommandControl()
var command1 = new Command1()
commandControl.execute(command1)
command2 = new Command2("my first prop")
commandControl.execute(command2)
command3 = new Command1()
commandControl.execute(command3)
command4 = new Command2("your command 2 prop")
commandControl.execute(command4)
// Undo specific command
commandControl.remove(command1)
// Undo last command
commandControl.undo()
Output
Command1: Executing
Command2: executing -- Prop1 value: my first prop
Command1: Executing
Command2: executing -- Prop1 value: your command 2 prop
Command1: Undoing
Command2: undoing
Example #2: UI Elements
Let’s take the example of printing UI elements.
Command [Interface and Concrete Classes]
// Command interface
interface UiCommand
print()
remove()
end interface
// Class for handlign Input element
class InputUi implements UiCommand
method print
// Write code to print the element
output "Printing Input"
end method
method remove
// Write code for removing the element
output "Removing Input"
end method
end class
// Class for handling Button element
class ButtonUi implements UiCommand
var final name: String
constructor(nameParam: String)
name = nameParam
end constructor
method print
// Write code to print the element
output "Printing " + name + " Button"
end method
method remove()
// Write code for removing the element
output "Removing " + name + " Button"
end method
end class
// Class for handling Table element
class TableUi implements UiCommand
method print
// Write code to print the element
output "Printing Table"
end method
method remove
// Write code for removing the element
output "Removing Table"
end method
end class
Controller
class UiControl
// Array to hold the list of executed commands
var private commandList[]
method addElement(UiCommand command) {
// Execute command
command.print()
// Store command in list to have a history
commandList.add(command)
end method
public void removeElement(UiCommand command) {
// Remove element
command.remove();
// Store command in list to have a history
commandList.remove(command)
end method
public void undo() {
// Get the last element
var lastElementIndex = commandList.size() - 1
var lastCommand = commandList.get(lastElementIndex)
// Remove last element
removeElement(lastCommand)
end method
end class
Demo
var uiControl = new UiControl()
var inputUi = new InputUi()
var tableUi = new TableUi()
var buttonUi = new ButtonUi("Submit")
uiControl.addElement(inputUi)
uiControl.addElement(tableUi)
uiControl.addElement(buttonUi)
// Remove specific element
uiControl.removeElement(tableUi)
// Add some new elements
uiControl.addElement(new ButtonUi("Cancel"))
uiControl.addElement(new TableUi())
uiControl.addElement(new InputUi())
uiControl.addElement(new ButtonUi("Wrong button"))
// Undo last to command
uiControl.undo()
uiControl.undo()
Output
Printing Input
Printing Table
Printing Submit Button
------------------------------------
Removing Table
------------------------------------
Printing Cancel Button
Printing Table
Printing Input
------------------------------------
Printing Wrong button Button
Removing Wrong button Button
Removing Input
Code Implementations
Use the following links to check Command pattern implementation in specific programming languages.