Clever Geek Handbook
📜 ⬆️ ⬇️

Team (design pattern)

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
Command.gif
Type ofbehavioral
Purposeto process the command as an object
Related TemplatesLinker , Keeper , Prototype , Single
Described in Design PatternsYes

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

C ++ source code
  # 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

C # Source Code
  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

Java source code
  / * 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

JavaScript source
  // 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

Python source code
  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

PHP5 source code
  <? 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

Ruby source code
  # 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

VB.NET source code
  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
Source - https://ru.wikipedia.org/w/index.php?title=Command_ ( design_pattern) )&oldid = 101267511


More articles:

  • 7.5 cm Gebirgsgeschütz 36
  • Lotus E20
  • Seam Kernels
  • Big Rigs: Over the Road Racing
  • Stalin State Museum
  • Buffer Lights
  • Medvedev, Nikolai Yakovlevich
  • Archaeological Museum of Westphalia-Lippe
  • Army Group "Liguria"
  • Dance Open

All articles

Clever Geek | 2019