Command ( eng. Command ) - behavioral design pattern used in object-oriented programming, representing the action. The command object contains the action itself and its parameters.
| Team | |
|---|---|
| Command | |
![]() | |
| Type of | behavioral |
| Purpose | to process the command as an object |
| Related Templates | Linker , Keeper , Prototype , Single |
| Described in Design Patterns | Yes |
Content
Purpose
Creating a structure in which the sending class and the receiving class are not directly dependent on each other. Organizing a callback to a class that includes the sender class.
Description
In object-oriented programming, a design pattern. A command is a behavioral pattern in which an object is used to encapsulate all the information needed to perform an action or trigger an event at a later time. This information includes the name of the method, the object that owns the method, and the values of the method parameters.
Four terms are always associated with the Command pattern: commands (command), command receiver (receiver), invoking commands (invoker) and client (client). The Command object knows about the receiver and calls the receiver method. The values of the receiver parameters are stored in the command. The caller (invoker) knows how to execute a command and, possibly, does the recording and recording of executed commands. The caller (invoker) knows nothing about a particular team, he knows only about the interface. Both objects (the calling object and several command objects) belong to the client object (client). The client decides which commands to execute and when. To execute a command, it passes the command object to the invoker.
Using command objects makes it easy to build common components that you need to delegate or execute method calls at any time without having to know the methods of the class or the parameters of the method. Using the calling object (invoker) allows you to enter a record of commands executed without the need to know the client about this accounting model (such records can be useful, for example, to implement undo and redo commands).
Application
The command pattern can be useful in the following cases.
- UI buttons and menu items
In Swing and Borland, the Delphi Action (action) is a command object. In addition to being able to execute a desired command, an Action can have an icon associated with it, a shortcut, a tooltip text, and so on. A button on a toolbar or a menu item can be fully initialized using only an Action object.
- Macro recording
If all user actions are represented as command objects, the program can record a sequence of actions, simply storing the list of command objects in the order in which they are performed. Then she can “reproduce” the same actions, performing the same command objects in the same sequence.
- Multi-level undo operations ( Undo )
If all user actions in the program are implemented as command objects, the program can save the stack of the last executed commands. When a user wants to cancel a command, the program simply pushes the last command object and executes its undo () method.
- Network
You can send command objects over the network to run on another machine, for example, a player’s action in a computer game.
- Progress Indicators
Suppose a program has a sequence of commands that it executes in order. If each command object has a getEstimatedDuration () method (get an estimated duration), the program can easily estimate the total duration of the process. It can show a progress bar that reflects how close the program is to completion of all tasks.
- Thread pools
A typical general-purpose thread pool class can have the addTask () method, which adds a work item to an internal job queue of pending tasks. It maintains a pool of threads that execute commands from the queue. Items in the queue are command objects. Typically, these objects implement a common interface, such as java.lang.Runnable , which allows the thread pool to run commands for execution, even if it was written without any knowledge of the specific tasks for which it will be used.
- Transactions
Similarly, the operation “cancellation” database management system (DBMS) or software installer can store a list of operations that have been or will be performed. If one of them fails, then all others can be canceled or discarded (usually called rollback). For example, if two interconnected database tables are to be updated, and the second update fails, the system may roll back the transaction so that the first table does not contain an invalid reference.
- Masters
Often the wizard (installation wizard or any other) presents several configuration pages for one action, which occurs only when the user clicks the “Finish” button on the last page. In these cases, the natural way to separate the user interface code from the application code is to implement the wizard using the command object. The command object is created when the wizard is first displayed. Each page of the wizard saves its changes in the command object, so the object is filled as the user transitions. The "Finish" button simply runs the execute () method.
Examples
C ++ Example
# include < iostream >
# include < vector >
# include < string >
using namespace std ;
class Document
{
vector < string > data ;
public :
Document ()
{
data . reserve ( 100 ); // at least for 100 lines
}
void Insert ( int line , const string & str )
{
if ( line <= data . size () )
data . insert ( data . begin () + line , str );
else
cout << "Error!" << endl ;
}
void Remove ( int line )
{
if ( ! ( line > data . size () ) )
data . erase ( data . begin () + line );
else
cout << "Error!" << endl ;
}
string & operator [] ( int x )
{
return data [ x ];
}
void Show ()
{
for ( int i = 0 ; i < data . size (); ++ i )
{
cout << i + 1 << "." << data [ i ] << endl ;
}
}
};
class Command
{
protected :
Document * doc ;
public :
virtual ~ Command () {}
virtual void Execute () = 0 ;
virtual void unExecute () = 0 ;
void setDocument ( Document * _doc )
{
doc = _doc ;
}
};
class InsertCommand : public Command
{
int line ;
string str ;
public :
InsertCommand ( int _line , const string & _str ): line ( _line ), str ( _str ) {}
void Execute ()
{
doc -> Insert ( line , str );
}
void unExecute ()
{
doc -> Remove ( line );
}
};
class Invoker
{
vector < Command *> DoneCommands ;
Document doc ;
Command * command ;
public :
void Insert ( int line , string str )
{
command = new InsertCommand ( line , str );
command -> setDocument ( & doc );
command -> Execute ();
DoneCommands . push_back ( command );
}
void Undo ()
{
if ( DoneCommands . size () == 0 )
{
cout << "There is nothing to undo!" << endl ;
}
else
{
command = DoneCommands . back ();
DoneCommands . pop_back ();
command -> unExecute ();
// Don't forget to delete command !!!
delete command ;
}
}
void Show ()
{
doc . Show ();
}
};
int main ()
{
char s = '1' ;
int line , line_b ;
string str ;
Invoker inv ;
while ( s ! = 'e' )
{
cout << "What to do: \ n1.Add a line \ n2.Undo last command" << endl ;
cin >> s ;
switch ( s )
{
case '1' :
cout << "What line to insert:" ;
cin >> line ;
- line ;
cout << "What to insert:" ;
cin >> str ;
inv . Insert ( line , str );
break ;
case '2' :
inv . Undo ();
break ;
}
cout << "$$$ DOCUMENT $$$" << endl ;
inv . Show ();
cout << "$$$ DOCUMENT $$$" << endl ;
}
}
C # Example
using System ;
using System.Collections.Generic ;
namespace Command
{
class program
{
static void Main ()
{
User user = new User ();
// call commands
user . Compute ( '+' , 100 );
user . Compute ( '-' , 50 );
user . Compute ( '*' , 10 );
user . Compute ( '/' , 2 );
// Undo the last 4 commands invoked
user . Undo ( 4 );
// Restore the last 3 canceled commands
user . Redo ( 3 );
// Prevent closing the console
Console . Read ();
}
}
// "Command": interface
interface ICommand
{
void Execute ();
void UnExecute ();
}
// "ConcreteCommand": specific team
class CalculatorCommand : ICommand
{
char @operator ;
int operand ;
Calculator calculator ;
public CalculatorCommand ( Calculator calculator ,
char @operator , int operand )
{
this . calculator = calculator ;
this . @operator = @operator ;
this . operand = operand ;
}
public char Operator
{
set { @operator = value ; }
}
public int Operand
{
set { operand = value ; }
}
public void Execute ()
{
calculator . Operation ( @operator , operand );
}
public void UnExecute ()
{
calculator . Operation ( GetReversed ( @operator ), operand );
}
// Private helper function: private helper functions
private charger GetReversed ( char @operator )
{
char reversed ;
switch ( @operator )
{
case '+' : reversed = '-' ; break ;
case '-' : reversed = '+' ; break ;
case '*' : reversed = '/' ; break ;
case '/' : reversed = '*' ; break ;
default : reversed = '' ; break ;
}
return reversed ;
}
}
// "Receiver": recipient
class Calculator
{
private int current = 0 ;
public void Operation ( char @operator , int operand )
{
switch ( @operator )
{
case '+' : current + = operand ; break ;
case '-' : current - = operand ; break ;
case '*' : current * = operand ; break ;
case '/' : current / = operand ; break ;
}
Console . WriteLine (
"Current value = {0,3} (following {1} {2})" ,
current @operator , operand );
}
}
// Invoker: the caller
class User
{
// Initializers
private Calculator calculator = new Calculator ();
private List < ICommand > commands = new List < ICommand > ();
private int current = 0 ;
public void Redo ( int levels )
{
Console . WriteLine ( "\ n ---- Redo {0} levels" , levels );
// Do return operations
for ( int i = 0 ; i < levels ; i ++)
if ( current < commands . Count )
commands [ current ++]. Execute ();
}
public void Undo ( int levels )
{
Console . WriteLine ( "\ n ---- Undo {0} levels" , levels );
// Do undo operations
for ( int i = 0 ; i < levels ; i ++)
if ( current > 0 )
commands [- current ]. UnExecute ();
}
public void Compute ( char @operator , int operand )
{
// Create an operation command and execute it.
ICommand command = new CalculatorCommand (
calculator , @operator , operand );
command . Execute ();
if ( current < commands . Count )
{
// If "inside undo" we start a new operation,
// it is necessary to chop off the list of commands following the current one
// otherwise, undo / redo will be incorrect
commands . RemoveRange ( current , commands . Count - current );
}
// Add the operation to the undo list
commands . Add ( command );
current ++;
}
}
}
Java Example
/ * the Invoker class * /
public class Switch {
private Command flipUpCommand ;
private Command flipDownCommand ;
public Switch ( Command flipUpCommand , Command flipDownCommand ) {
this . flipUpCommand = flipUpCommand ;
this . flipDownCommand = flipDownCommand ;
}
public void flipUp () {
flipUpCommand . execute ();
}
public void flipDown () {
flipDownCommand . execute ();
}
}
/ * Receiver class * /
public class Light {
public Light () { }
public void turnOn () {
System . out . println ( "The light is on" );
}
public void turnOff () {
System . out . println ( "The light is off" );
}
}
/ * the Command interface * /
public interface Command {
void execute ();
}
/ * the Command for turning on the light * /
public class TurnOnLightCommand implements Command {
private Light theLight ;
public TurnOnLightCommand ( Light light ) {
this . theLight = light ;
}
public void execute () {
theLight . turnOn ();
}
}
/ * the Command for turning off the light * /
public class TurnOffLightCommand implements Command {
private Light theLight ;
public TurnOffLightCommand ( Light light ) {
this . theLight = light ;
}
public void execute () {
theLight . turnOff ();
}
}
/ * The test class * /
public class TestCommand {
public static void main ( String [] args ) {
Light l = new Light ();
Command switchUp = new TurnOnLightCommand ( l );
Command switchDown = new TurnOffLightCommand ( l );
Switch s = new Switch ( switchUp , switchDown );
s . flipUp ();
s . flipDown ();
}
}
JavaScript example
// Command: abstract command
function Command () {
this . execute = function () {};
this . unExecute = function () {};
}
// ConcreteCommand: specific team
function CalculatorCommand () {
var calculator ;
var operator ;
var operand ;
this . execute = function ( newCalculator , newOperator , newOperand ) {
// set the command parameters
if ( typeof ( newCalculator ) == "object" && typeof ( newOperator ) == "string" && typeof ( newOperand ) == "number" ) {
calculator = newCalculator ;
operator = newOperator ;
operand = newOperand ;
}
// command execution
calculator . operation ( operator , operand );
};
this . unExecute = function () {
// execute the reverse command
calculator . operation ( undo ( operator ), operand );
};
function undo ( operator ) {
// function will return the inverse operator
// if desired, you can use the closure and not pass the operator
switch ( operator ) {
case '+' : return '-' ; break ;
case '-' : return '+' ; break ;
}
return '' ; // default result
}
}
CalculatorCommand . prototype = new Command ();
CalculatorCommand . prototype . constructor = CalculatorCommand ;
// Receiver: recipient
function Calculator () {
var val = 0 ;
this . operation = function ( operator , operand ) {
// perform the operation
switch ( operator ) {
case '+' :
val + = operand ;
debug ( operator , operand );
break ;
case '-' :
val - = operand ;
debug ( operator , operand );
break ;
default :
alert ( "Unknown operator" );
break ;
}
};
function debug ( operator , operand ) {
alert ( "Current value:" + val + "\ nOperation:" + operator + operand );
}
}
// Invoker: caller
function User () {
var calculator = new Calculator ();
var commands = []; // array of commands
current = 0 ; // number of the current command
this . compute = function ( operator , operand ) {
var newCommand = new CalculatorCommand ();
if ( current < commands . length - 1 ) {
// if "inside undo" we start a new operation,
// it is necessary to chop off the list of commands following the current one
// otherwise, undo / redo will be incorrect
commands . splice ( current );
}
newCommand . execute ( calculator , operator , operand );
commands . push ( newCommand );
current ++ ;
};
this . undo = function ( levels ) {
alert ( "cancel (" + levels + ")" );
for ( i = 0 ; i < levels ; i ++ ) {
if ( current > 0 ) {
commands [ - current ]. unExecute ();
}
}
};
this . redo = function ( levels ) {
alert ( "return (" + levels + ")" );
for ( i = 0 ; i < levels ; i ++ ) {
if ( current < commands . length ) {
commands [ current ++ ]. execute ();
}
}
};
}
// use
var u = new User ();
u . compute ( "+" , 2 ); // 2, "+2"
u . compute ( "+" , 3 ); // 5, "+3"
u . compute ( "-" , 1 ); // 4, "-1"
u . compute ( "+" , 6 ); // 10, "+6"
u . undo ( 3 ); // 4, "-6"
// 5, "+1"
// 2, "-3"
u . redo ( 2 ); // 5, "+3"
// 4, "-1"
u . undo ( 2 ); // 5, "+1"
// 2, "-3"
u . compute ( "+" , 8 ); // 10, "+8"
u . undo ( 1 ); // 2, "-8"
u . redo ( 2 ); // 10, "+8"
// excess of commands
u . compute ( "+" , 9 ); // 19, "+9"
Python Example
from abc import ABCMeta , abstractmethod
class Troop :
"" "
Receiver - object of the military detachment
"" "
def move ( self , direction : str ) -> None :
"" "
Start moving in a certain direction
"" "
print ( 'The squad started moving {}' . format ( direction ))
def stop ( self ) -> None :
"" "
Stay
"" "
print ( 'Squad Stopped' )
class Command ( metaclass = ABCMeta ):
"" "
Base class for all teams
"" "
@abstractmethod
def execute ( self ) -> None :
"" "
Start the command
"" "
pass
@abstractmethod
def unexecute ( self ) -> None :
"" "
Cancel command execution
"" "
pass
class AttackCommand ( Command ):
"" "
Command to execute the attack
"" "
def __init__ ( self , troop : Troop ) -> None :
"" "
Constructor.
: param troop: squad with which the team is associated
"" "
self . troop = troop
def execute ( self ) -> None :
self . troop . move ( 'forward' )
def unexecute ( self ) -> None :
self . troop . stop ()
class RetreatCommand ( Command ):
"" "
Command to perform the retreat
"" "
def __init__ ( self , troop : Troop ) -> None :
"" "
Constructor.
: param troop: squad with which the team is associated
"" "
self . troop = troop
def execute ( self ) -> None :
self . troop . move ( 'back' )
def unexecute ( self ) -> None :
self . troop . stop ()
class TroopInterface :
"" "
Invoker - an interface through which you can give commands to a specific squad
"" "
def __init__ ( self , attack : AttackCommand , retreat : RetreatCommand ) -> None :
"" "
Constructor.
: param attack: command to execute an attack
: param retreat: command to execute retreat
"" "
self . attack_command = attack
self . retreat_command = retreat
self . current_command = None # command currently executing
def attack ( self ) -> None :
self . current_command = self . attack_command
self . attack_command . execute ()
def retreat ( self ) -> None :
self . current_command = self . retreat_command
self . retreat_command . execute ()
def stop ( self ) -> None :
if self . current_command :
self . current_command . unexecute ()
self . current_command = None
else :
print ( 'The unit cannot stop, because it does not move' )
if __name__ == '__main__' :
troop = Troop ()
interface = TroopInterface ( AttackCommand ( troop ), RetreatCommand ( troop ))
interface . attack ()
interface . stop ()
interface . retreat ()
interface . stop ()
PHP5 Example
<? php / ** * Abstract "command" class * @abstract * / abstract class Command { public abstract Execute (); public abstract function UnExecute (); } / ** * Class of a specific "command" * / class CalculatorCommand extends Command { / ** * Current command operation * * @var string * / public $ operator ; / ** * Current operand * * @var mixed * / public $ operand ; / ** * Class for which the command * * @ @var object of class Calculator * is intended / public $ calculator ; / ** * Constructor * * @param object $ calculator * @param string $ operator * @param mixed $ operand * / public function __construct ( $ calculator , $ operator , $ operand ) { $ this -> calculator = $ calculator ; $ this -> operator = $ operator ; $ this -> operand = $ operand ; } / ** * Overriden function parent :: Execute () * / public function Execute () { $ this -> calculator -> Operation ( $ this -> operator , $ this -> operand ); } / ** * Overdefined function parent :: UnExecute () * / public function UnExecute () { $ this -> calculator -> Operation ( $ this -> Undo ( $ this -> operator ), $ this -> operand ); } / ** * What action needs to be undone? * * @private * @param string $ operator * @return string * / private function Undo ( $ operator ) { // find the reverse for each action taken switch ( $ operator ) { case '+' : $ undo = '-' ; break ; case '-' : $ undo = '+' ; break ; case '*' : $ undo = '/' ; break ; case '/' : $ undo = '*' ; break ; default : $ undo = '' ; break ; } return $ undo ; } } / ** * Class receiver and executor of "commands" * / class Calculator { / ** * Current result of command execution * * @private * @var int * / private $ curr = 0 ; public function Operation ( $ operator , $ operand ) { // select an operator to calculate the result switch ( $ operator ) { case '+' : $ this -> curr + = $ operand ; break ; case '-' : $ this -> curr - = $ operand ; break ; case '*' : $ this -> curr * = $ operand ; break ; case '/' : $ this -> curr / = $ operand ; break ; } print ( "Current result = $ this-> curr (after performing $ operator c $ operand )" ); } } / ** * Class calling commands * / class User { / ** * This class will receive execution commands * * @private * @var object of class Calculator * / private $ calculator ; / ** * Array of operations * * @private * @var array * / private $ commands = array (); / ** * Current command in operations array * * @private * @var int * / private $ current = 0 ; public function __construct () { // create an instance of the class that will execute the $ this -> calculator = new Calculator () command ; } / ** * Function of returning canceled commands * * @param int $ levels number of operations returned * / public function Redo ( $ levels ) { print ( " \ n ---- Repeat $ levels operations" ); // Do return operations for ( $ i = 0 ; $ i < $ levels ; $ i ++ ) if ( $ this -> current < count ( $ this -> commands ) - 1 ) $ this -> commands [ $ this -> current ++ ] -> Execute (); } / ** * Command cancel function * * @param int $ levels number of operations canceled * / public function Undo ( $ levels ) { print ( " \ n ---- Cancel $ levels operations" ); // Do cancel operations for ( $ i = 0 ; $ i < $ levels ; $ i ++ ) if ( $ this -> current > 0 ) $ this -> commands [ - $ this -> current ] -> UnExecute (); } / ** * Command execution function * * @param string $ operator * @param mixed $ operand * / public function Compute ( $ operator , $ operand ) { // Create an operation command and execute it $ command = new CalculatorCommand ( $ this -> calculator , $ operator , $ operand ); $ command -> Execute (); // Add an operation to the array of operations and increase the counter of the current operation $ this -> commands [] = $ command ; $ this -> current ++ ; } } $ user = new User (); // Arbitrary commands $ user -> Compute ( '+' , 100 ); $ user -> Compute ( '-' , 50 ); $ user -> Compute ( '*' , 10 ); $ user -> Compute ( '/' , 2 ); // Cancel 4 commands $ user -> Undo ( 4 ); // Return 3 canceled commands. $ user -> Redo ( 3 ); Ruby Example
# Receiver
class Calculator
def initialize
@val = 0
end
def perform_operation ( operator , operand )
case operator
when '+'
@val + = operand
when '-'
@val - = operand
when '*'
@val * = operand
when '/'
@val / = operand
end
display ( operator , operand )
end
private
def display ( operator , operand )
puts "=> # { @val } , # { operator } # { operand } \ n "
end
end
# Abstract command
class Command
def initialize ( calculator , operand )
@calculator = calculator
@operand = operand
@operator = "'
end
def execute
@calculator . perform_operation ( @operator , @operand )
end
def unexecute
@calculator . perform_operation ( inversed_operator , @operand )
end
def operator
raise NotImplementedError
end
private
def inversed_operator
case @operator
when '+' then '-'
when '-' then '+'
when '*' then '/'
when '/' then '*'
else
raise ArgumentError
end
end
end
# Concrete commands
class Addition < Command
def initialize ( calculator , operand )
super
@operator = '+'
end
end
class Subtraction < Command
def initialize ( calculator , operand )
super
@operator = '-'
end
end
class Multiplication < Command
def initialize ( calculator , operand )
super
@operator = '*'
end
end
class Division < Command
def initialize ( calculator , operand )
super
@operator = '/'
end
end
# Invoker
class CommandManager
def initialize
@commands = []
@current = 0
end
def execute ( command )
# trim the commands list when undo
@commands = @commands . slice ( 0 , @current ) if @current < @commands . count - 1
command . execute
@commands << command
@current + = 1
end
def undo ( levels )
puts "Undo # { levels } levels"
levels . times do
@current - = 1
@commands [ @current ]. unexecute rescue puts ( 'Incorrect index' ) and break
end
end
def redo ( levels )
puts "Redo # { levels } levels"
levels . times do
@commands [ @current ]. execute rescue puts ( 'Incorrect index' ) and break
@current + = 1
end
end
end
# Client
class User
attr_reader : command_manager
def initialize
@calculator = Calculator . new
@command_manager = CommandManager . new
end
def compute ( operator , operand )
case operator
when '+' then @command_manager . execute ( Addition . new ( @calculator , operand ))
when '-' then @command_manager . execute ( Subtraction . new ( @calculator , operand ))
when '*' then @command_manager . execute ( Multiplication . new ( @calculator , operand ))
when '/' then @command_manager . execute ( Division . new ( @calculator , operand ))
end
end
end
u = User . new
u . compute ( '+' , 2 )
u . compute ( '+' , 3 )
u . compute ( '-' , 1 )
u . compute ( '+' , 6 )
u . command_manager undo ( 3 )
u . command_manager redo ( 2 )
u . command_manager undo ( 2 )
u . compute ( '+' , 8 )
u . command_manager undo ( 1 )
u . command_manager redo ( 2 )
u . compute ( '+' , 9 )
# console output:
# => 2, +2
# => 5, +3
# => 4, -1
# => 10, +6
# Undo 3 levels
# => 4, -6
# => 5, +1
# => 2, -3
# Redo 2 levels
# => 5, +3
# => 4, -1
# Undo 2 levels
# => 5, +1
# => 2, -3
# => 10, +8
# Undo 1 levels
# => 2, -8
# Redo 2 levels
# => 10, +8
# Incorrect index
# => 19, +9
VB.NET Example
Imports System.Collections.Generic
Namespace Command
Class program
Shared Sub Main ()
'Create user.
Dim user as new user ()
'Let him do something.
user . Compute ( "+" c , 100 )
user . Compute ( "-" c , 50 )
user . Compute ( "*" c , 10 )
user . Compute ( "/" c , 2 )
'Cancel 4 commands
user . Undo ( 4 )
'We will return 3 canceled commands.
user . Redo ( 3 )
'We are waiting for user input and finish.
Console . Read ()
End sub
End class
'"Command": Abstract Command
MustInherit Class Command
Public MustOverride Sub Execute ()
Public MustOverride Sub UnExecute ()
End class
'"ConcreteCommand": specific team
Class CalculatorCommand
Inherits command
Private m_operator As Char
Private m_operand As Integer
Private calculator as calculator
'Constructor
Public Sub New ( ByVal calculator As Calculator , ByVal [ operator ] As Char , ByVal operand As Integer )
Me . calculator = calculator
Me . m_operator = [ operator ]
Me . m_operand = operand
End sub
Public WriteOnly Property [ Operator ] () As Char
Set ( ByVal value As Char )
m_operator = value
End set
End property
Public WriteOnly Property Operand () As Integer
Set ( ByVal value As Integer )
m_operand = value
End set
End property
Public Overrides Sub Execute ()
calculator . Operation ( m_operator , m_operand )
End sub
Public Overrides Sub UnExecute ()
calculator . Operation ( Undo ( m_operator ), m_operand )
End sub
'Private helper function: private helper functions
Private Function Undo ( ByVal [ operator ] As Char ) As Char
Dim undo__1 As Char
Select Case [ operator ]
Case "+" c
undo__1 = "-" c
Exit select
Case "-" c
undo__1 = "+" c
Exit select
Case "*" c
undo__1 = "/" c
Exit select
Case "/" c
undo__1 = "*" c
Exit select
Case else
undo__1 = "" c
Exit select
End select
Return undo__1
End function
End class
'"Receiver": recipient
Class calculator
Private curr As Integer = 0
Public Sub Operation ( ByVal [ operator ] As Char , ByVal operand As Integer )
Select Case [ operator ]
Case "+" c
curr + = operand
Exit select
Case "-" c
curr - = operand
Exit select
Case "*" c
curr * = operand
Exit select
Case "/" c
curr / = operand
Exit select
End select
Console . WriteLine ( "Current value = {0,3} (following {1} {2})" , curr , [ operator ] , operand )
End sub
End class
'Invoker': caller
Class User
'Initializers
Private calculator As New Calculator ()
Private commands As New List ( Of Command ) ()
Private current As Integer = 0
Public Sub Redo ( ByVal levels As Integer )
Console . WriteLine ( vbLf & "---- Redo {0} levels" , levels )
'Doing the return operations
For i As Integer = 0 To levels - 1
If current < commands . Count - 1 Then
commands ( System . Math . Max . ( System . Threading . Interlocked . Increment ( current ), current - 1 )). Execute ()
End if
Next
End sub
Public Sub Undo ( ByVal levels As Integer )
Console . WriteLine ( vbLf & "---- Undo {0} levels" , levels )
'Do cancel operations
For i As Integer = 0 To levels - 1
If current > 0 Then
commands ( System . Threading . Interlocked . Decrement ( current )). UnExecute ()
End if
Next
End sub
Public Sub Compute ( ByVal [ operator ] As Char , ByVal operand As Integer )
'Create an operation command and execute it
Dim command As Command = New CalculatorCommand ( calculator , [ operator ] , operand )
command . Execute ()
'Add operation to the undo list
commands . Add ( command )
current + = 1
End sub
End class
End namespace
Links
- Design Pattern Command (Command) - purpose, description, implementation in C ++, advantages and disadvantages
