Decorator Pattern
What is the Decorator Design Pattern
- The decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically without affecting the behavior of other objects from the same class.
Lets use examples of Tacos when we keep wrapping/decorating the tacos with different toppings to see how the decorator pattern works!
UML for Taco
Taco Header (Taco.h)
#ifndef TACO_H_
#define TACO_H_
#include <string>
class Taco
{
public:
virtual ~Taco() {}
virtual double GetCost() = 0;
virtual std::string GetDescription() = 0;
};
#endif /* TACO_H_ */
Small Taco (SmallTaco.h)
#ifndef SMALL_TACO_H
#define SMALL_TACO_H
#include "Taco.h"
class SmallTaco : public Taco {
public:
SmallTaco();
virtual ~SmallTaco();
virtual double GetCost();
virtual std::string GetDescription();
};
SmallTaco::SmallTaco() {}
SmallTaco::~SmallTaco() {}
double SmallTaco::GetCost()
{
return 5.99;
}
std::string SmallTaco::GetDescription()
{
return std::string("Small Taco");
}
#endif /* SMALL_TACO_H */
Large Taco (LargeTaco.h)
#ifndef LARGE_TACO_H
#define LARGE_TACO_H
#include "Taco.h"
class LargeTaco : public Taco {
public:
LargeTaco();
virtual ~LargeTaco();
virtual double GetCost();
virtual std::string GetDescription();
};
LargeTaco::LargeTaco() {}
LargeTaco::~LargeTaco() {}
double LargeTaco::GetCost()
{
return 8.99;
}
std::string LargeTaco::GetDescription()
{
return std::string("Large Taco");
}
#endif /* LARGE_TACO_H */
Taco Decorator Header (TacoItemsDecorator.h)
#ifndef TACOITEMSDECORATOR_H_
#define TACOITEMSDECORATOR_H_
#include "Taco.h"
class TacoItemsDecorator : public Taco {
protected:
Taco * _taco;
public:
TacoItemsDecorator(Taco * taco);
virtual ~TacoItemsDecorator();
virtual double GetCost();
virtual std::string GetDescription();
};
TacoItemsDecorator::TacoItemsDecorator(Taco * taco) : _taco(taco){}
TacoItemsDecorator::~TacoItemsDecorator(){}
double TacoItemsDecorator::GetCost(){
return _taco->GetCost();
}
std::string TacoItemsDecorator::GetDescription()
{
return _taco->GetDescription();
}
#endif /* TACOITEMSDECORATOR_H_ */
Lettuce (Lettuce.h)
#ifndef LETTUCE_H_
#define LETTUCE_H_
#include "TacoItemsDecorator.h"
class Lettuce : public TacoItemsDecorator {
public:
Lettuce(Taco * taco);
virtual ~Lettuce();
virtual std::string GetDescription();
};
Lettuce::Lettuce(Sub * sub) : TacoItemsDecorator(sub) {}
Lettuce::~Lettuce() {}
std::string Lettuce::GetDescription()
{
return _taco->GetDescription() + std::string(", Lettuce");
}
#endif /* LETTUCE_H_ */
Steak (Steak.h)
##ifndef STEAK_H_
#define STEAK_H_
#include "TacoItemsDecorator.h"
class Steak : public TacoItemsDecorator {
public:
Steak(Taco * taco);
virtual ~Steak();
virtual std::string GetDescription();
};
Steak::Steak(Taco * taco) : TacoItemsDecorator(taco) {}
Steak::~Steak() {}
std::string Steak::GetDescription()
{
return _taco->GetDescription() + ", Steak";
}
Cheese (Cheese.h)
#ifndef CHEESE_H_
#define CHEESE_H_
#include "TacoItemsDecorator.h"
class Cheese : public TacoItemsDecorator {
public:
Cheese(Taco * taco);
virtual ~Cheese();
virtual double GetCost(); // Added Cost for Cheese
virtual std::string GetDescription();
};
Cheese::Cheese(Taco * taco) : TacoItemsDecorator(taco) {}
Cheese::~Cheese() {}
double Cheese::GetCost()
{
return _taco->GetCost() + 0.50;
}
std::string Cheese::GetDescription()
{
return _taco->GetDescription() + std::string(", Cheese");
}
#endif /* CHEESE_H_ */
Salsa (Salsa.h)
#ifndef SALSA_H_
#define SALSA_H_
#include "TacoItemsDecorator.h"
class Salsa : public TacoItemsDecorator {
public:
Salsa(Taco * taco);
virtual ~Salsa();
virtual std::string GetDescription();
};
Salsa::Salsa(Taco * taco) : TacoItemsDecorator(taco) {}
Salsa::~Salsa() {}
std::string Salsa::GetDescription()
{
return _taco->GetDescription() + std::string(", Salsa");
}
#endif /* SALSA_H_ */
Chicken Header (Chicken.h)
#ifndef CHICKEN_H_
#define CHICKEN_H_
#include "TacoItemsDecorator.h"
class Chicken : public TacoItemsDecorator {
public:
Chicken(Taco * taco);
virtual ~Chicken();
virtual std::string GetDescription();
};
Chicken::Chicken(Taco * taco) : TacoItemsDecorator(taco) {}
Chicken::~Chicken() {}
std::string Chicken::GetDescription()
{
return _taco->GetDescription() + std::string(", Chicken");
}
#endif /* CHICKEN_H_ */
Guac Header (Guac.h)
#ifndef GUAC_H_
#define GUAC_H_
#include "TacoItemsDecorator.h"
class Guac : public TacoItemsDecorator {
public:
Guac(Taco * taco);
virtual ~Guac();
virtual double GetCost();
virtual std::string GetDescription();
};
Guac::Guac(Taco * taco): TacoItemsDecorator(taco) {}
Guac::~Guac() {}
double Guac::GetCost()
{
return _taco->GetCost() + 1.00;
}
std::string Guac::GetDescription()
{
return _taco->GetDescription() + std::string(", Guac");
}
#endif /* GUAC_H_ */
Main File (main.cpp)
#include "SmallTaco.h"
#include "LargeTaco.h"
#include "Lettuce.h"
#include "Steak.h"
#include "Salsa.h"
#include "Cheese.h"
#include "Guac.h"
#include "Chicken.h"
#include <iostream>
int main()
{
SmallTaco smallTaco;
Chicken smallChicken(&smallTaco);
Lettuce smallLettuce(&smallChicken);
Steak smallSteak(&smallLettuce);
Salsa smallSalsa(&smallSteak);
Cheese smallCheese(&smallSteak);
Guac smallGuac(&smallCheese);
Taco * taco = &smallGuac;
std::cout << "Description : " << taco->GetDescription() << "\n";
std::cout << "Cost : " << taco->GetCost() << "\n\n";
LargeTaco largeTaco;
Chicken largeChicken(&largeTaco);
Lettuce largeLettuce(&largeChicken);
Steak largeSteak(&largeLettuce);
Salsa largeSalsa(&largeSteak);
Cheese largeCheese(&largeSalsa);
Guac largeGuac(&largeCheese);
Taco * large_taco = &largeGuac;
std::cout << "Description : " << large_taco->GetDescription() << "\n";
std::cout << "Cost : " << large_taco->GetCost() << "\n\n";
}
Output
Description : Small Taco, Chicken, Lettuce, Steak, Cheese, Guac
Cost : 8.49
Description : Large Taco, Chicken, Lettuce, Steak, Salsa, Cheese, Guac
Cost : 11.49