Command

Summary:  Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Frequency of use:
Medium high

UML class diagram

Participants

The classes and objects participating in this pattern are:

  • Command  (Command)
    • declares an interface for executing an operation
  • ConcreteCommand  (CalculatorCommand)
    • defines a binding between a Receiver object and an action
    • implements Execute by invoking the corresponding operation(s) on Receiver
  • Client  (CommandApp)
    • creates a ConcreteCommand object and sets its receiver
  • Invoker  (User)
    • asks the command to carry out the request
  • Receiver  (Calculator)
    • knows how to perform the operations associated with carrying out the request.

Structural code in C#

This structural code demonstrates the Command pattern which stores requests as objects allowing clients to execute or playback the requests.

     

using System;

 

namespace DoFactory.GangOfFour.Command.Structural

{

  /// <summary>

  /// MainApp startup class for Structural

  /// Command Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      // Create receiver, command, and invoker

      Receiver receiver = new Receiver();

      Command command = new ConcreteCommand(receiver);

      Invoker invoker = new Invoker();

 

      // Set and execute command

      invoker.SetCommand(command);

      invoker.ExecuteCommand();

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Command' abstract class

  /// </summary>

  abstract class Command

  {

    protected Receiver receiver;

 

    // Constructor

    public Command(Receiver receiver)

    {

      this.receiver = receiver;

    }

 

    public abstract void Execute();

  }

 

  /// <summary>

  /// The 'ConcreteCommand' class

  /// </summary>

  class ConcreteCommand : Command

  {

    // Constructor

    public ConcreteCommand(Receiver receiver) :

      base(receiver)

    {

    }

 

    public override void Execute()

    {

      receiver.Action();

    }

  }

 

  /// <summary>

  /// The 'Receiver' class

  /// </summary>

  class Receiver

  {

    public void Action()

    {

      Console.WriteLine("Called Receiver.Action()");

    }

  }

 

  /// <summary>

  /// The 'Invoker' class

  /// </summary>

  class Invoker

  {

    private Command _command;

 

    public void SetCommand(Command command)

    {

      this._command = command;

    }

 

    public void ExecuteCommand()

    {

      _command.Execute();

    }

  }

}

Output
Called Receiver.Action()

Real-world code in C#

This real-world code demonstrates the Command pattern used in a simple calculator with unlimited number of undo's and redo's. Note that in C#  the word 'operator' is a keyword. Prefixing it with '@' allows using it as an identifier.

    

using System;

using System.Collections.Generic;

 

namespace DoFactory.GangOfFour.Command.RealWorld

{

  /// <summary>

  /// MainApp startup class for Real-World

  /// Command Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      // Create user and let her compute

      User user = new User();

 

      // User presses calculator buttons

      user.Compute('+', 100);

      user.Compute('-', 50);

      user.Compute('*', 10);

      user.Compute('/', 2);

 

      // Undo 4 commands

      user.Undo(4);

 

      // Redo 3 commands

      user.Redo(3);

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Command' abstract class

  /// </summary>

  abstract class Command

  {

    public abstract void Execute();

    public abstract void UnExecute();

  }

 

  /// <summary>

  /// The 'ConcreteCommand' class

  /// </summary>

  class CalculatorCommand : Command

  {

    private char _operator;

    private int _operand;

    private Calculator _calculator;

 

    // Constructor

    public CalculatorCommand(Calculator calculator,

      char @operator, int operand)

    {

      this._calculator = calculator;

      this._operator = @operator;

      this._operand = operand;

    }

 

    // Gets operator

    public char Operator

    {

      set { _operator = value; }

    }

 

    // Get operand

    public int Operand

    {

      set { _operand = value; }

    }

 

    // Execute new command

    public override void Execute()

    {

      _calculator.Operation(_operator, _operand);

    }

 

    // Unexecute last command

    public override void UnExecute()

    {

      _calculator.Operation(Undo(_operator), _operand);

    }

 

    // Returns opposite operator for given operator

    private char Undo(char @operator)

    {

      switch (@operator)

      {

        case '+': return '-';

        case '-': return '+';

        case '*': return '/';

        case '/': return '*';

        default: throw new

         ArgumentException("@operator");

      }

    }

  }

 

  /// <summary>

  /// The 'Receiver' class

  /// </summary>

  class Calculator

  {

    private int _curr = 0;

 

    public void Operation(char @operator, int operand)

    {

      switch (@operator)

      {

        case '+': _curr += operand; break;

        case '-': _curr -= operand; break;

        case '*': _curr *= operand; break;

        case '/': _curr /= operand; break;

      }

      Console.WriteLine(

        "Current value = {0,3} (following {1} {2})",

        _curr, @operator, operand);

    }

  }

 

  /// <summary>

  /// The 'Invoker' class

  /// </summary>

  class User

  {

    // Initializers

    private Calculator _calculator = new Calculator();

    private List<Command> _commands = new List<Command>();

    private int _current = 0;

 

    public void Redo(int levels)

    {

      Console.WriteLine("\n---- Redo {0} levels ", levels);

      // Perform redo operations

      for (int i = 0; i < levels; i++)

      {

        if (_current < _commands.Count - 1)

        {

          Command command = _commands[_current++];

          command.Execute();

        }

      }

    }

 

    public void Undo(int levels)

    {

      Console.WriteLine("\n---- Undo {0} levels ", levels);

      // Perform undo operations

      for (int i = 0; i < levels; i++)

      {

        if (_current > 0)

        {

          Command command = _commands[--_current] as Command;

          command.UnExecute();

        }

      }

    }

 

    public void Compute(char @operator, int operand)

    {

      // Create command operation and execute it

      Command command = new CalculatorCommand(

        _calculator, @operator, operand);

      command.Execute();

 

      // Add command to undo list

      _commands.Add(command);

      _current++;

    }

  }

}

Output
Current value = 100 (following + 100)
Current value =  50 (following - 50)
Current value = 500 (following * 10)
Current value = 250 (following / 2)

---- Undo 4 levels
Current value = 500 (following * 2)
Current value =  50 (following / 10)
Current value = 100 (following + 50)
Current value =   0 (following - 100)

---- Redo 3 levels
Current value = 100 (following + 100)
Current value =  50 (following - 50)
Current value = 500 (following * 10)

.NET Optimized code in C#


The .NET optimized code demonstrates the same real-world situation as above but uses modern, built-in .NET features, such as, generics, reflection, LINQ, lambda functions, and more. You can find an example on our Singleton pattern page.

All other patterns, and so much more, are available in our Dofactory .NET product.


Dofactory .NET includes the Gang of Four and Enterprise patterns, but also many other innovations including our Ultra-Clean™ Architecture, powerful low-code tactics, Rapid Application Development (RAD) techniques, and much more.

Accelerate your application development to where you can write entire solutions in just 33 days!. This unique package will change your outlook on development and your career.  Here's what is included:






Dofactory .NET
.NET Developer Pack




Learn More



  • 69 gang-of-four pattern projects
  • 46 head-first pattern projects
  • Fowler's enterprise patterns
  • Multi-tier patterns
  • Convention over configuration
  • Active Record and CQRS patterns
  • Repository and Unit-of-Work patterns
  • MVC, MVP, & MVVM patterns
  • SparkTM Rapid App Dev (RAD) data access
  • Complete Analytics, Dashboard App
  • Complete Art Shop, Ecommerce App
  • Complete SaaS, Multi-Tenant App
  • Complete CRM, Customer Relationship App
  • 33-Day App Factory™
  • Everything 100% source code




Stay Inspired!
Join other developers and designers who have already signed up for our mailing list.
Terms     Privacy     Licensing       EULA       Sitemap      
© Data & Object Factory, LLC.
Made with    in Austin, Texas