C++ - Design pattern - Strategy

The Strategy design pattern allows to change behaviour of a program depending on a context.

It means that a single class can manage many others without knowing that those classes even exist.

Interesting isn't it?

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

First of all

In this example we are going to use a Context as a manager, an IStrategy as interface, Strategy1 and Strategy2 as dashboards.

Indeed, we will simulate dashboards that could display three components.

This number "three" is important in our example because this is the interface that definites it.

Of course, we could use four, five and so on components to display but in our example we chose arbitrarily three components.

Then a user will have an account either normal or premium.

And, depending of the dashboard, some components will be displayed or not.

The Strategy1 is able to display a text, an image and a video.

The Strategy2 is able to display a curve, a graphic and a table.

Other Strategy classes, like Strategy4 or Strategy5, could display other kind of components.

But in our case and for simplicity we have only two dashboards.

Lets' code a bit.

Code

Context.cpp

#include <memory>
#include <iostream>
#include "Context.h"
#include "IStrategy.h"

// Badprog.com

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

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

//-----------------------------------------------------------------------------
// setContext
//-----------------------------------------------------------------------------
void Context::setStrategy(const std::shared_ptr<IStrategy> &strategy, IStrategy::ENUM_ACCOUNT account) {
_strategy = strategy;
_account = account;
}

//-----------------------------------------------------------------------------
// displayComponents
//-----------------------------------------------------------------------------
void Context::dealWithStrategy() {
// finds the account rights
switch (_account)
{
case IStrategy::ACCOUNT_PREMIUM:
std::cout << std::endl;
std::cout << "=== Premium account ===" << std::endl;
_strategy->setComponent1(true);
_strategy->setComponent2(true);
_strategy->setComponent3(true);
break;

case IStrategy::ACCOUNT_NORMAL:
std::cout << std::endl;
std::cout << "=== Normal account ===" << std::endl;
_strategy->setComponent1(true);
_strategy->setComponent2(false);
_strategy->setComponent3(false);
break;
 
default:
std::cout << "=== Wrong account ===" << std::endl;
_strategy->setComponent1(false);
_strategy->setComponent2(false);
_strategy->setComponent3(false);
break;
}

// displays corresponding components depending of user rights
_strategy->displayComponents();
}

Context.h

#ifndef __BADPROG_CONTEXT_H__
#define __BADPROG_CONTEXT_H__

// Badprog.com

//#include <memory>
#include "IStrategy.h"

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

  void setStrategy(const std::shared_ptr<IStrategy> &strategy, IStrategy::ENUM_ACCOUNT account);
  void dealWithStrategy();

private:
  IStrategy::ENUM_ACCOUNT _account;
  std::shared_ptr<IStrategy> _strategy;
};

#endif // __BADPROG_CONTEXT_H__

IStrategy.h

#ifndef __BADPROG_ISTRATEGY_H__
#define __BADPROG_ISTRATEGY_H__

// Badprog.com

class IStrategy {
public:
  enum ENUM_ACCOUNT { ACCOUNT_PREMIUM, ACCOUNT_NORMAL };
public:
  virtual ~IStrategy() {};
  virtual void displayComponents() = 0;
  virtual void setComponent1(bool b) = 0;
  virtual void setComponent2(bool b) = 0;
  virtual void setComponent3(bool b) = 0;
  virtual const bool getComponent1() const = 0;
  virtual const bool getComponent2() const = 0;
  virtual const bool getComponent3() const = 0;

protected:
  virtual void displayComponent1() = 0;
  virtual void displayComponent2() = 0;
  virtual void displayComponent3() = 0;
  bool _visibilityComponent1;
  bool _visibilityComponent2;
  bool _visibilityComponent3;
};

#endif // __BADPROG_ISTRATEGY_H__

main.cpp

#include <memory>
#include <iostream>
#include "IStrategy.h"
#include "Strategy1.h"
#include "Strategy2.h"
#include "Context.h"

// Badprog.com

//-----------------------------------------------------------------------------
// main
//-----------------------------------------------------------------------------
int main()
{
Context context;
auto strategy1 = std::make_shared<Strategy1>(); // strategy 1
auto strategy2 = std::make_shared<Strategy2>(); // strategy 2
 
//
    std::cout << std::endl << "Strategy 1";
context.setStrategy(strategy1, IStrategy::ACCOUNT_NORMAL);
    context.dealWithStrategy();
    context.setStrategy(strategy1, IStrategy::ACCOUNT_PREMIUM);
    context.dealWithStrategy();
//
    std::cout << std::endl << "Strategy 2";
context.setStrategy(strategy2, IStrategy::ACCOUNT_NORMAL);
    context.dealWithStrategy();
    context.setStrategy(strategy2, IStrategy::ACCOUNT_PREMIUM);
    context.dealWithStrategy();
}

Strategy1.cpp

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

// Badprog.com

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

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

//-----------------------------------------------------------------------------
// displayComponents
//-----------------------------------------------------------------------------
void Strategy1::displayComponents() {
if (true == getComponent1()) {
displayComponent1();
}
if (true == getComponent2()) {
displayComponent2();
}
if (true == getComponent3()) {
displayComponent3();
}
}

//-----------------------------------------------------------------------------
// displayComponent1
//-----------------------------------------------------------------------------
void Strategy1::displayComponent1() {
std::cout << "Displaying a text." << std::endl;
}

//-----------------------------------------------------------------------------
// displayComponent2
//-----------------------------------------------------------------------------
void Strategy1::displayComponent2() {
std::cout << "Displaying an image." << std::endl;
}

//-----------------------------------------------------------------------------
// displayComponent3
//-----------------------------------------------------------------------------
void Strategy1::displayComponent3() {
std::cout << "Displaying a video." << std::endl;
}

//-----------------------------------------------------------------------------
// setComponent1
//-----------------------------------------------------------------------------
void Strategy1::setComponent1(bool b) {
_visibilityComponent1 = b;
}

//-----------------------------------------------------------------------------
// setComponent2
//-----------------------------------------------------------------------------
void Strategy1::setComponent2(bool b) {
_visibilityComponent2 = b;
}

//-----------------------------------------------------------------------------
// setComponent3
//-----------------------------------------------------------------------------
void Strategy1::setComponent3(bool b) {
_visibilityComponent3 = b;
}

//-----------------------------------------------------------------------------
// getComponent1
//-----------------------------------------------------------------------------
const bool Strategy1::getComponent1() const {
return _visibilityComponent1;
}

//-----------------------------------------------------------------------------
// getComponent2
//-----------------------------------------------------------------------------
const bool Strategy1::getComponent2() const {
return _visibilityComponent2;
}

//-----------------------------------------------------------------------------
// getComponent3
//-----------------------------------------------------------------------------
const bool Strategy1::getComponent3() const {
return _visibilityComponent3;
}

Strategy1.h

#ifndef __BADPROG_STRATEGY1_H__
#define __BADPROG_STRATEGY1_H__

// Badprog.com

#include "IStrategy.h"

class Strategy1 : public IStrategy {
public:
  Strategy1();
  ~Strategy1();

  void displayComponents() override;
  void setComponent1(bool b) override;
  void setComponent2(bool b) override;
  void setComponent3(bool b) override;
  const bool getComponent1() const override;
  const bool getComponent2() const override;
  const bool getComponent3() const override;

private:
  void displayComponent1() override;
  void displayComponent2() override;
  void displayComponent3() override;
};

#endif // __BADPROG_STRATEGY1_H__

Strategy2.cpp

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

// Badprog.com

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

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

//-----------------------------------------------------------------------------
// displayComponents
//-----------------------------------------------------------------------------
void Strategy2::displayComponents() {
if (true == getComponent1()) {
displayComponent1();
}
if (true == getComponent2()) {
displayComponent2();
}
if (true == getComponent3()) {
displayComponent3();
}
}

//-----------------------------------------------------------------------------
// displayComponent1
//-----------------------------------------------------------------------------
void Strategy2::displayComponent1() {
std::cout << "Displaying a curve." << std::endl;
}

//-----------------------------------------------------------------------------
// displayComponent2
//-----------------------------------------------------------------------------
void Strategy2::displayComponent2() {
std::cout << "Displaying a graphic." << std::endl;
}

//-----------------------------------------------------------------------------
// displayComponent3
//-----------------------------------------------------------------------------
void Strategy2::displayComponent3() {
std::cout << "Displaying a table." << std::endl;
}

//-----------------------------------------------------------------------------
// setComponent1
//-----------------------------------------------------------------------------
void Strategy2::setComponent1(bool b) {
_visibilityComponent1 = b;
}

//-----------------------------------------------------------------------------
// setComponent2
//-----------------------------------------------------------------------------
void Strategy2::setComponent2(bool b) {
_visibilityComponent2 = b;
}

//-----------------------------------------------------------------------------
// setComponent3
//-----------------------------------------------------------------------------
void Strategy2::setComponent3(bool b) {
_visibilityComponent3 = b;
}

//-----------------------------------------------------------------------------
// getComponent1
//-----------------------------------------------------------------------------
const bool Strategy2::getComponent1() const {
return _visibilityComponent1;
}

//-----------------------------------------------------------------------------
// getComponent2
//-----------------------------------------------------------------------------
const bool Strategy2::getComponent2() const {
return _visibilityComponent2;
}

//-----------------------------------------------------------------------------
// getComponent3
//-----------------------------------------------------------------------------
const bool Strategy2::getComponent3() const {
return _visibilityComponent3;
}

Strategy2.h

#ifndef __BADPROG_STRATEGY2_H__
#define __BADPROG_STRATEGY2_H__

// Badprog.com

#include "IStrategy.h"

class Strategy2 : public IStrategy {
public:
  Strategy2();
  ~Strategy2();

  void displayComponents() override;
  void setComponent1(bool b) override;
  void setComponent2(bool b) override;
  void setComponent3(bool b) override;
  const bool getComponent1() const override;
  const bool getComponent2() const override;
  const bool getComponent3() const override;

private:
  void displayComponent1() override;
  void displayComponent2() override;
  void displayComponent3() override;
};

#endif // __BADPROG_STRATEGY2_H__

 

Compiling, linking and running

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

Result

Context

Strategy1

Strategy2


Strategy 1

=== Normal account ===

Displaying a text.


=== Premium account ===

Displaying a text.

Displaying an image.

Displaying a video.


Strategy 2

=== Normal account ===

Displaying a curve.


=== Premium account ===

Displaying a curve.

Displaying a graphic.

Displaying a table.


~Strategy1


~Context


~Strategy2

Conclusion

As you can see there is one Context and depending on the IStrategy (Strategy1 or Strategy2) the components displayed are not the same.

Furthermore by only changing the account type we also changed the number of components to display from the dashboard.

This is quite interesting because we could add plenty of IStrategy classes with three different components to display.

And for that we would need only one Context to manage all dashboards.

Good job, once again, you got it. laugh

Add new comment

Plain text

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