C++ - Design pattern - Decorator

The Decorator design pattern allows an object to be decorated in different ways not by inheriting from another class but by adding features directly to this object.

It's main interest is to avoid multiplication of classes that would be almost the same as the main one.

This design pattern has an interesting architecture even if not so easy to understand at first.

Let's see how this Decorator design pattern works.

First of all

Link to the Github repository: 

The heart of the Decorator design pattern is a kind of recursion or something like a linked list.

Each time a data is changed, we call the Decorator object in order to call the IDecorator passed to this Decorator.

And this until we don't have any IDecorator to use.

As final step we return the object we wanted to decorate.

So it's not the main object that decorates itself but the decorator that adds features to the main object, that's an important point.

To illustrate this explanation we're going to use an example with a DShipTiny class that we will decorate with a Shield, a Weapon and a Bomb.

Each decorator got a weight and so each time we add a decorator, the ShipTiny weight increases.

At the end the final weight is the sum of the ShipTiny default weight plus all other decorators.

Code

Decorator.cpp

// Badprog.com

#include <memory>
#include <iostream>
#include <string>
#include "Decorator.h"

//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
Decorator::Decorator(std::unique_ptr<IDecorator> decorator)
: _decorator(std::move(decorator)) {
std::cout << "Decorator created." << std::endl;
}

//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
Decorator::~Decorator() {
std::cout << "Decorator destroyed." << std::endl;
}

//-----------------------------------------------------------------------------
// getWeight
//-----------------------------------------------------------------------------
double Decorator::getWeight(double weight) {
std::cout << "Weight from Decorator." << std::endl;
_weight += weight;
return _decorator->getWeight(_weight);
}

 

Decorator.h

#ifndef __BADPROG_DECORATOR_H__
#define __BADPROG_DECORATOR_H__

// Badprog.com

#include <memory>
#include "IDecorator.h"

//-----------------------------------------------------------------------------
// Decorator
//-----------------------------------------------------------------------------
class Decorator : public IDecorator
{
public:
  Decorator(std::unique_ptr<IDecorator> decorator = nullptr);
  virtual ~Decorator();

virtual double getWeight(double weight) override;

private:
double _weight;
std::unique_ptr<IDecorator>_decorator;
};

#endif // __BADPROG_DECORATOR_H__

 

DecoratorBomb.cpp

// Badprog.com

#include <iostream>
#include <memory>
#include <string>
#include "DecoratorBomb.h"

//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
DecoratorBomb::DecoratorBomb(std::unique_ptr<IDecorator> decorator)
: Decorator(std::move(decorator)) {
std::cout << "Decorator bomb created." << std::endl;
_weight = 50;
}

//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
DecoratorBomb::~DecoratorBomb() {
std::cout << "Decorator bomb destroyed." << std::endl;
}

//-----------------------------------------------------------------------------
// getWeight
//-----------------------------------------------------------------------------
double DecoratorBomb::getWeight(double weight) {
std::cout << "Weight from bomb." << std::endl;
_weight += weight;
std::cout << "Weight = " << _weight << std::endl;
return Decorator::getWeight(_weight);
}

 

DecoratorBomb.h

#ifndef __BADPROG_DECORATORBOMB_H__
#define __BADPROG_DECORATORBOMB_H__

// Badprog.com

#include <memory>
#include <string>
#include "Decorator.h"

//-----------------------------------------------------------------------------
// DecoratorBomb
//-----------------------------------------------------------------------------
class DecoratorBomb : public Decorator
{
public:
  DecoratorBomb(std::unique_ptr<IDecorator> decorator = nullptr);
  ~DecoratorBomb();

  double getWeight(double weigth) override;

private:
double _weight;
};

#endif // __BADPROG_DECORATORBOMB_H__

 

DecoratorShield.cpp

// Badprog.com

#include <iostream>
#include <memory>
#include <string>
#include "DecoratorShield.h"

//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
DecoratorShield::DecoratorShield(std::unique_ptr<IDecorator> decorator)
: Decorator(std::move(decorator)) {
std::cout << "Decorator shield created." << std::endl;
_weight = 150;
}

//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
DecoratorShield::~DecoratorShield() {
std::cout << "Decorator shield destroyed." << std::endl;
}

//-----------------------------------------------------------------------------
// getWeight
//-----------------------------------------------------------------------------
double DecoratorShield::getWeight(double weight) {
std::cout << "Weight from shield." << std::endl;
_weight += weight;
std::cout << "Weight = " << _weight << std::endl;
return Decorator::getWeight(_weight);
}

DecoratorShield.h

#ifndef __BADPROG_DECORATORSHIELD_H__
#define __BADPROG_DECORATORSHIELD_H__

// Badprog.com

#include <memory>
#include <string>
#include "Decorator.h"

//-----------------------------------------------------------------------------
// DecoratorShield
//-----------------------------------------------------------------------------
class DecoratorShield : public Decorator
{
public:
  DecoratorShield(std::unique_ptr<IDecorator> decorator = nullptr);
  ~DecoratorShield();

  double getWeight(double weight) override;

private:
double _weight;
};

#endif // __BADPROG_DECORATORSHIELD_H__

 

DecoratorWeapon.cpp

#include "stdafx.h"

// Badprog.com

#include <iostream>
#include <memory>
#include <string>
#include "DecoratorWeapon.h"

//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
DecoratorWeapon::DecoratorWeapon(std::unique_ptr<IDecorator> decorator)
: Decorator(std::move(decorator)) {
std::cout << "Decorator weapon created." << std::endl;
_weight = 75;
}

//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
DecoratorWeapon::~DecoratorWeapon() {
std::cout << "Decorator weapon destroyed." << std::endl;
}

//-----------------------------------------------------------------------------
// getWeight
//-----------------------------------------------------------------------------
double DecoratorWeapon::getWeight(double weight) {
std::cout << "Weight from weapon." << std::endl;
_weight += weight;
std::cout << "Weight = " << _weight << std::endl;
return Decorator::getWeight(_weight);
}

DecoratorWeapon.h

#ifndef __BADPROG_DECORATORWEAPON_H__
#define __BADPROG_DECORATORWEAPON_H__

// Badprog.com

#include <memory>
#include <string>
#include "Decorator.h"

//-----------------------------------------------------------------------------
// DecoratorWeapon
//-----------------------------------------------------------------------------
class DecoratorWeapon : public Decorator
{
public:
  //DecoratorWeapon();
  DecoratorWeapon(std::unique_ptr<IDecorator> decorator = nullptr);
  ~DecoratorWeapon();

  double getWeight(double weight) override;
  
private:
double _weight;
};

#endif // __BADPROG_DECORATORWEAPON_H__

main.cpp

// Badprog.com

#include <memory>
#include <iostream>
#include "DShipTiny.h"
#include "DecoratorShield.h"
#include "DecoratorWeapon.h"
#include "DecoratorBomb.h"

//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
int main()
{
  auto ship = std::make_unique<DecoratorShield>(
          std::make_unique<DecoratorWeapon>(
            std::make_unique<DecoratorBomb>(
              std::make_unique<DShipTiny>())));

  double weightByDefault = 100;
  std::cout << "New weight after all decorators: " <<
    ship->getWeight(weightByDefault) << std::endl;

return 0;
}

 

DShipTiny.cpp

// Badprog.com

#include <iostream>
#include <string>
#include "DShipTiny.h"

//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
DShipTiny::DShipTiny() {
std::cout << "ShipTiny created." << std::endl;
}

//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
DShipTiny::~DShipTiny() {
std::cout << "ShipTiny destroyed." << std::endl;
}

//-----------------------------------------------------------------------------
// decorate
//-----------------------------------------------------------------------------
double DShipTiny::getWeight(double weight) {
std::cout << "Final weight from DShipTiny." << std::endl;
return weight; // last and final return from the recursion
}

 

DShipTiny.h

#ifndef __BADPROG_DSHIPTINY_H__
#define __BADPROG_DSHIPTINY_H__

// Badprog.com

#include "IDecorator.h"

//-----------------------------------------------------------------------------
// DShipTiny
//-----------------------------------------------------------------------------
class DShipTiny : public IDecorator
{
public:
  DShipTiny();
  ~DShipTiny();

  double getWeight(double weight) override;
};

#endif // __BADPROG_DSHIPTINY_H__

 

IDecorator.h

#ifndef __BADPROG_IDECORATOR_H__
#define __BADPROG_IDECORATOR_H__

// Badprog.com

#include <memory>
#include <string>

//-----------------------------------------------------------------------------
// IDecorator
//-----------------------------------------------------------------------------
class IDecorator
{
public:
  virtual ~IDecorator() {};
  virtual double getWeight(double weight) = 0;

};

#endif // __BADPROG_IDECORATOR_H__

 

Compiling, linking and running

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

Result

ShipTiny created.

Decorator created.

Decorator bomb created.

Decorator created.

Decorator weapon created.

Decorator created.

Decorator shield created.

Weight from shield.

Weight = 250

Weight from Decorator.

Weight from weapon.

Weight = 325

Weight from Decorator.

Weight from bomb.

Weight = 375

Weight from Decorator.

Final weight from DShipTiny.

New weight after all decorators: 375

Decorator shield destroyed.

Decorator destroyed.

Decorator weapon destroyed.

Decorator destroyed.

Decorator bomb destroyed.

Decorator destroyed.

ShipTiny destroyed.

Conclusion

The DShipTiny object was initialized with a weight of 100 and after all decorators added, this weight is passed to 375.

With the debug trace we can see how the different weights have been added successively.

And it was exactly what we wanted to have as a result.

Once again good job, you did it. laugh

Add new comment

Plain text

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