C++ - Design pattern - Command

The Command design pattern creates a list of objects on which we're going to apply a generic method.

It's a bit unusal because an object will request a method as parameter.

This makes the Command design pattern a versatile one but maybe not so easy to handle at first.

Once again an interesting study case.

Let's see that in this Command design pattern tutorial.

First of all

There are many ways to use this Command design pattern.

It clearly depends on what you need in your program.

For example you can have Command classes already existing in your code so you'll have to add only an interface to them.

You could also have only one receiver that will handle every action, so don't need to specifiy it each time on the command (even if it's always better to think to the future and anticipated the fact that other receivers will be necessary).

Or maybe you want a generic Command that will take a receiver and an action as parameters but you don't want an interface for the receivers, a template will be a solution.

So according to your needs the end will be different.

In general, this design pattern needs a function pointer as a callback.

The declaration of a function pointer is a bit esoteric so don't be afraid of that.

With this function pointer we will tell the Command which method apply on the object passed as  parameter.

The object and the method will be both used as a pair by the Command.

So we need them, they are essential in this design pattern.

It' also possible to not use any method as second parameter for the Command but in this case we'd assume that there would be only one method in the Receiver.

Anyway the key to this pattern is the execute() method that will be used every time the Invoker launch a command.

Lets' code a bit.

Code

CommandFly.cpp

#include "CommandFly.h"
#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
CommandFly::CommandFly() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// CTOR parameterized
//-----------------------------------------------------------------------------
CommandFly::CommandFly(std::unique_ptr<MainApplication> application)
  : _application(std::move(application)) {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
CommandFly::~CommandFly() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// execute
//-----------------------------------------------------------------------------
void CommandFly::execute() {
  std::cout << __FUNCTION__ << std::endl;
  _application->goodEvening();
}

 

CommandFly.h

#ifndef __BADPROG_COMMAND_FLY_H__
#define __BADPROG_COMMAND_FLY_H__

// Badprog.com

#include <memory>
#include "ICommand.h"
#include "MainApplication.h"

class CommandFly : public ICommand
{
public:
  CommandFly();
  CommandFly(std::unique_ptr<MainApplication> application); // needs a pointer because we need an IReceiver (interface)
  ~CommandFly();

  void execute()  override;

private:
  std::unique_ptr<MainApplication> _application;
};

#endif // __BADPROG_COMMAND_FLY_H__

 

CommandRocket.cpp

#include "CommandRocket.h"
#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
CommandRocket::CommandRocket() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
CommandRocket::CommandRocket(std::unique_ptr<SpecialObject> specialObject)
  : _specialObject(std::move(specialObject)) {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
CommandRocket::~CommandRocket() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// execute
//-----------------------------------------------------------------------------
void CommandRocket::execute() {
  std::cout << __FUNCTION__ << std::endl;
  _specialObject->goodMorning();
}

 

CommandRocket.h

#ifndef __BADPROG_COMMAND_ROCKET_H__
#define __BADPROG_COMMAND_ROCKET_H__

// Badprog.com

#include <memory>
#include "ICommand.h"
#include "SpecialObject.h"

class CommandRocket : public ICommand
{
public:
  CommandRocket();
  CommandRocket(std::unique_ptr<SpecialObject> specialObject);
  ~CommandRocket();

  void execute()  override;

private:
  std::unique_ptr<SpecialObject> _specialObject;
};

#endif // __BADPROG_COMMAND_ROCKET_H__

 

main.cpp

//
#include <memory>
#include "Invoker.h"
#include "CommandFly.h"
#include "CommandRocket.h"
#include "ReceiverAlpha.h"
#include "ReceiverBeta.h"
#include "MainApplication.h"
#include "SpecialObject.h"

// Badprog.com

//-----------------------------------------------------------------------------
// main
//-----------------------------------------------------------------------------
int main() {

  // init
  auto receiverAlpha    = std::make_shared<ReceiverAlpha>();
  auto receiverBeta   = std::make_shared<ReceiverBeta>();
  auto mainApplication  = std::make_unique<MainApplication>();
  auto specialObject    = std::make_unique<SpecialObject>();
  auto commandFly     = std::make_unique<CommandFly>(std::move(mainApplication));
  auto commandRocket    = std::make_unique<CommandRocket>(std::move(specialObject));
  auto commandBasicAlpha1 = std::make_unique<CommandBasic<ReceiverAlpha>>(receiverAlpha, &ReceiverAlpha::greetings);
  auto commandBasicAlpha2 = std::make_unique<CommandBasic<ReceiverAlpha>>(receiverAlpha, &ReceiverAlpha::hello);
  auto commandBasicAlpha3 = std::make_unique<CommandBasic<ReceiverAlpha>>(receiverAlpha, &ReceiverAlpha::goodbye);
  auto commandBasicBeta   = std::make_unique<CommandBasic<ReceiverBeta>>(receiverBeta, &ReceiverBeta::howAreYou);
  Invoker invoker;

  // invoker
  invoker.addCommand(std::move(commandBasicAlpha1));
  invoker.addCommand(std::move(commandBasicAlpha2));
  invoker.addCommand(std::move(commandBasicAlpha3));
  invoker.addCommand(std::move(commandBasicBeta));
  invoker.addCommand(std::move(commandFly));
  invoker.addCommand(std::move(commandRocket));
  invoker.executeVectorOfCommands();

  return 0;
}

 

ICommand.h

#ifndef __BADPROG_ICOMMAND_H__
#define __BADPROG_ICOMMAND_H__

#include <iostream>
#include <memory>

// Badprog.com

class ICommand
{
public:
  virtual ~ICommand() = 0;
  virtual void execute() = 0;

protected:
  ICommand& operator=(const ICommand&) { return *this; }
};

inline ICommand::~ICommand() {}

//_____________________________________________________________________________
// Template
//_____________________________________________________________________________

//-----------------------------------------------------------------------------
// CommandBasic
//-----------------------------------------------------------------------------
template <typename T>
class CommandBasic : public ICommand {
public:
  typedef void (T:: *Action)(); // Action is a function pointer to T

  //-----------------------------------------------------------------------------
  // CTOR
  //-----------------------------------------------------------------------------
  // CommandBasic(T *receiver, Action action) :
  CommandBasic(std::shared_ptr<T> receiver, Action action)
    : _receiver(receiver), _action(action) {
    std::cout << __FUNCTION__ << std::endl;
  }

  //-----------------------------------------------------------------------------
  // DTOR
  //-----------------------------------------------------------------------------
  ~CommandBasic() {
    std::cout << __FUNCTION__ << std::endl;
  }

  // in case we want to copy a CommandBasic outside the template
  CommandBasic(const CommandBasic &other) : _receiver(std::make_shared(*other._receiver)) {}
  CommandBasic(CommandBasic&& other) : _receiver(std::move(other._receiver)) {}
  CommandBasic& operator=(CommandBasic other) {
    std::swap(*this, other);
    return *this;
  }
  //-----------------------------------------------------------------------------
  // execute
  //-----------------------------------------------------------------------------
  virtual void execute() {
    std::cout << __FUNCTION__ << std::endl;
    (_receiver.get()->*_action)();
  }

private:
  Action  _action;  // Action is already a pointer
  std::shared_ptr<T>  _receiver;
};

#endif // __BADPROG_ICOMMAND_H__

 

Invoker.cpp

#include "Invoker.h"
#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
Invoker::Invoker() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
Invoker::~Invoker() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// addCommand
//-----------------------------------------------------------------------------
void Invoker::addCommand(std::unique_ptr<ICommand> command) {
  std::cout << __FUNCTION__ << std::endl;
  _vectorOfCommands.push_back(std::move(command));
}

//-----------------------------------------------------------------------------
// executeVectorOfCommands
//-----------------------------------------------------------------------------
void Invoker::executeVectorOfCommands() const {
  std::cout << std::endl;
  std::cout << __FUNCTION__ << std::endl;
  for (unsigned int i = 0; i < _vectorOfCommands.size(); ++i) {
    _vectorOfCommands[i]->execute();
  }
  std::cout << std::endl;
}

 

Invoker.h

#ifndef __BADPROG_INVOKER_H__
#define __BADPROG_INVOKER_H__

// Badprog.com

#include <memory>
#include <vector>
#include "ICommand.h"

class Invoker
{
public:
  Invoker();
  ~Invoker();
  void addCommand(std::unique_ptr<ICommand> command);
  void executeVectorOfCommands() const;

private:
  std::vector<std::unique_ptr<ICommand>> _vectorOfCommands;
};

#endif // __BADPROG_INVOKER_H__

 

MainApplication.cpp

#include "MainApplication.h"
#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
MainApplication::MainApplication() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
MainApplication::~MainApplication() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// goodEvening
//-----------------------------------------------------------------------------
void MainApplication::goodEvening() const {
  std::cout << __FUNCTION__ << std::endl;
}

 

MainApplication.h

#ifndef __BADPROG_MAIN_APPLICATION_H__
#define __BADPROG_MAIN_APPLICATION_H__

#include <iostream>

// Badprog.com

class MainApplication
{
public:
  MainApplication();
  ~MainApplication();

  void goodEvening() const;
};

#endif // __BADPROG_MAIN_APPLICATION_H__

 

ReceiverAlpha.cpp

#include "ReceiverAlpha.h"
#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
ReceiverAlpha::ReceiverAlpha() : _greetings("Have a nice day :p") {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
ReceiverAlpha::~ReceiverAlpha() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// hello
//-----------------------------------------------------------------------------
void ReceiverAlpha::hello() {
  std::cout << __FUNCTION__ << std::endl;
  _greetings = "Hello world! :D";
  std::cout << _greetings << std::endl;
}

//-----------------------------------------------------------------------------
// greetings
//-----------------------------------------------------------------------------
void ReceiverAlpha::greetings() {
  std::cout << __FUNCTION__ << std::endl;
  std::cout << _greetings << std::endl;
}

//-----------------------------------------------------------------------------
// goodbye
//-----------------------------------------------------------------------------
void ReceiverAlpha::goodbye() {
  std::cout << __FUNCTION__ << std::endl;
  _greetings = "Goodbye see you soon ;)";
  std::cout << _greetings << std::endl;
}

 

ReceiverAlpha.h

#ifndef __BADPROG_RECEIVER_ALPHA_H__
#define __BADPROG_RECEIVER_ALPHA_H__

// Badprog.com

#include <string>

class ReceiverAlpha
{
public:
  ReceiverAlpha();
  ~ReceiverAlpha();

  void hello();
  void goodbye();
  void greetings();

private:
  std::string _greetings;
};

#endif // __BADPROG_RECEIVER_ALPHA_H__

 

ReceiverBeta.cpp

#include "ReceiverBeta.h"
#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
ReceiverBeta::ReceiverBeta() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
ReceiverBeta::~ReceiverBeta() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// howAreYou
//-----------------------------------------------------------------------------
void ReceiverBeta::howAreYou() {
  std::cout << __FUNCTION__ << std::endl;
}

 

ReceiverBeta.h

#ifndef __BADPROG_RECEIVER_BETA_H__
#define __BADPROG_RECEIVER_BETA_H__

// Badprog.com

class ReceiverBeta
{
public:
  ReceiverBeta();
  ~ReceiverBeta();

  void howAreYou();
};

#endif // __BADPROG_RECEIVER_BETA_H__

 

SpecialObject.cpp

#include "SpecialObject.h"

#include <iostream>

// Badprog.com

//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
SpecialObject::SpecialObject() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
SpecialObject::~SpecialObject() {
  std::cout << __FUNCTION__ << std::endl;
}

//-----------------------------------------------------------------------------
// goodMorning
//-----------------------------------------------------------------------------
void SpecialObject::goodMorning() const {
  std::cout << __FUNCTION__ << std::endl;
}

 

SpecialObject.h

#ifndef __BADPROG_SPECIAL_OBJECT_H__
#define __BADPROG_SPECIAL_OBJECT_H__

#include <iostream>

// Badprog.com

class SpecialObject
{
public:
  SpecialObject();
  ~SpecialObject();

  void goodMorning() const;
};

#endif // __BADPROG_SPECIAL_OBJECT_H__

 

Compiling, linking and running

g++ *.cpp -o go.exe -std=c++1y ; ./go.exe

Result

ReceiverAlpha::ReceiverAlpha

ReceiverBeta::ReceiverBeta

MainApplication::MainApplication

SpecialObject::SpecialObject

CommandFly::CommandFly

CommandRocket::CommandRocket

CommandBasic<class ReceiverAlpha>::CommandBasic

CommandBasic<class ReceiverAlpha>::CommandBasic

CommandBasic<class ReceiverAlpha>::CommandBasic

CommandBasic<class ReceiverBeta>::CommandBasic

Invoker::Invoker

Invoker::addCommand

Invoker::addCommand

Invoker::addCommand

Invoker::addCommand

Invoker::addCommand

Invoker::addCommand


Invoker::executeVectorOfCommands

CommandBasic<class ReceiverAlpha>::execute

ReceiverAlpha::greetings

Have a nice day :p

CommandBasic<class ReceiverAlpha>::execute

ReceiverAlpha::hello

Hello world! :D

CommandBasic<class ReceiverAlpha>::execute

ReceiverAlpha::goodbye

Goodbye see you soon ;)

CommandBasic<class ReceiverBeta>::execute

ReceiverBeta::howAreYou

CommandFly::execute

MainApplication::goodEvening

CommandRocket::execute

SpecialObject::goodMorning


Invoker::~Invoker

CommandBasic<class ReceiverAlpha>::~CommandBasic

CommandBasic<class ReceiverAlpha>::~CommandBasic

CommandBasic<class ReceiverAlpha>::~CommandBasic

CommandBasic<class ReceiverBeta>::~CommandBasic

CommandFly::~CommandFly

MainApplication::~MainApplication

CommandRocket::~CommandRocket

SpecialObject::~SpecialObject

ReceiverBeta::~ReceiverBeta

ReceiverAlpha::~ReceiverAlpha

Conclusion

An interesting way to handle different kind of Commands.

Good job if you got it! cool

Comments

Comment: 

This is excellent - struggled at first but then <light bulb *ON*>

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.