Design Patterns

Command



Design Pattern Type: Behavioral

GoF Statement of Intent:


Encapsulate a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
Brief Overview:



An object is used to represent and encapsulate all the information needed to call a method on an object at a later time. This may include the method name, the object that contains the method and the arguments to be passed to the method. The Client instantiates the command object and provides all the information required to make the call at a later time. The Invoker decides when the method should be called. The Receiver is an instance of the class that contains the code for the method being called. This allows the creation of objects (the invokers) which can execute methods at the time of their choosing without needing to know the owner of the method or the parameters.
UML Diagram:

Discussion and In-class Example:

In the Command Design Pattern we used two examples. In the first we illustrated the basic idea of the Command where a customer (Client) enters the Objectville Diner and places an order (Command) with Flo,s the waitress (Invoker). Flo doesn't know anything about how to prepare the customer's order. All she does is give the order (calls command.execute()) to Earl, the short-order cook (Receiver). Earl is the one who knows how to prepare the customer's meal (perform the require action). We say that the Invoker is decoupled from the Command, i.e. Flo doesn't need to know anything about preparing food. She is just the "messanger".



We also looked at the example of the home remote control and saw how to decouple the button pressing (Invoker) from the command (Receiver) objects. We also saw how simple it was to add the undo action by adding an undo() function to each Command object.

Header Defining a RemoteControl class
class RemoteControl
{
     private:
          Command *onCommands[7];
          Command *offCommands[7];
          Command *undoCommand;
     public:
          RemoteControl();
          void setCommand(int slot,
                      Command *onCommand,
                      Command *offCommand);
          void onButtonPushed(int slot);
          void offButtonPushed(int slot);
}


Implementation of the RemoteControl class
//--------------------------------
// Constructor - initializes all
//  commands to NoCommand
//--------------------------------
RemoteControl::RemoteControl()
{
     for(int i=0; i<7; i++)
     {
          onCommands[i] = new NoCommand();
          offCommands[i] = new NoCommand();
     }
     undoCommand = new NoCommand();
}

//--------------------------------
// Set an on and off command for
//  a particular slot.
//--------------------------------
void RemoteControl::setCommand(int slot,
                      Command onCommand,
                      Command offCommand)
{
     onCommands[slot] = onCommand;
     offCommands[slot] = offCommand;
}

//--------------------------------
// Execute an "ON" button pressed
//   action.
//--------------------------------
void RemoteControl::onButtonPushed(int slot)
{
     onCommands[slot]->execute();
     undoCommand = onCommands[slot];
}

//--------------------------------
// Execute an "OFF" button pressed
//   action.
//--------------------------------
 void RemoteControl::offButtonPushed(int slot)
{
     offCommands[slot]->execute();
     undoCommand = offCommands[slot];
}

//---------------------------------
// Execute an "UNDO" button pressed
//   action.
//---------------------------------
void RemoteControl::undoButtonPushed()
{
     undoCommand->undo;
}


UML Class diagram of the NoCommand class



Implementation of the LightOn command class
class LightOnCommand::Command
{
   private:
      Light *light;
   public:
      LightOnCommand(Light *light)
      {
         this->light = light;
      }
      void execute()
      {
         light->on();
      }
     void undo()
      {
         light->off();
      }
}


Implementation of the LightOFF command class
class LightOffCommand::Command
{
   private:
      Light *light;
   public:
      LightOffCommand(Light *light)
      {
         this->light = light;
      }
      void execute()
      {
         light->off();
      }
     void undo()
      {
         light->on();
      }
}