Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Decorator Design Pattern in C++

I have found this decorator design pattern on the internet here :

// CPP program to demonstrate
// Decorator pattern
#include <iostream>
#include <string>
using namespace std;

// Component
class MilkShake
{
public:
    virtual string Serve() = 0;
    virtual float price() = 0;
};


// Concrete Component
class BaseMilkShake : public MilkShake
{
public:
    string Serve()
    {
        return "MilkShake";
    }

    float price()
    {
        return 30;
    }
};

// Decorator
class MilkShakeDecorator: public MilkShake
{
protected:
    MilkShake *m_MilkShake;
public:

    MilkShakeDecorator(MilkShake *baseMilkShake): m_MilkShake(baseMilkShake){}

    string Serve()
    {
        return m_MilkShake->Serve();
    }

    float price()
    {
        return m_MilkShake->price();
    }
};


// Concrete Decorator
class MangoMilkShake: public MilkShakeDecorator
{
public:
    MangoMilkShake(MilkShake *baseMilkShake): MilkShakeDecorator(baseMilkShake){}

    string Serve()
    {
        return m_MilkShake->Serve() + " decorated with Mango ";
    }
    float price()
    {
        return m_MilkShake->price() + 40;
    }
};


class VanillaMilkShake: public MilkShakeDecorator
{
public:
    VanillaMilkShake(MilkShake *baseMilkShake): MilkShakeDecorator(baseMilkShake){}

    string Serve()
    {
        return m_MilkShake->Serve() + " decorated with Vanilla ";
    }
    float price()
    {
        return m_MilkShake->price() + 80;
    }
};

int main()
{
MilkShake *baseMilkShake = new BaseMilkShake();
cout << "Basic Milk shake \n";
cout << baseMilkShake -> Serve() << endl;
cout << baseMilkShake -> price() << endl;

MilkShake *decoratedMilkShake = new MangoMilkShake(baseMilkShake);
cout << "Mango decorated Milk shake \n";
cout << decoratedMilkShake -> Serve() << endl;
cout << decoratedMilkShake -> price() << endl;
    
delete decoratedMilkShake;

decoratedMilkShake = new VanillaMilkShake(baseMilkShake);
cout << "Vanilla decorated Milk shake \n";
cout << decoratedMilkShake -> Serve() << endl;
cout << decoratedMilkShake -> price() << endl;

delete decoratedMilkShake;
delete baseMilkShake;
return 0;
}

But I am wondering: why should the decorator class exist? If I delete it and use only the concrete decorators than everything still works as before. The only downside I see is the fact that I have to use a private pointer to MilkShake in the concrete decorators.

// CPP program to demonstrate
// Decorator pattern
#include <iostream>
#include <string>
using namespace std;
 
// Component
class MilkShake
{
public:
    virtual string Serve() = 0;
    virtual float price() = 0;
};
 
 
// Concrete Component 
class BaseMilkShake : public MilkShake
{
public:
    string Serve()
    {
        return "MilkShake";
    }
 
    float price()
    {
        return 30;
    }
};
 
class MangoMilkShake: public MilkShake
{
private:
    MilkShake *m_MilkShake;
public:
    MangoMilkShake(MilkShake *baseMilkShake): m_MilkShake(baseMilkShake){}
 
    string Serve()
    {
        return m_MilkShake->Serve() + " decorated with Mango ";
    }
    float price()
    {
        return m_MilkShake->price() + 40;
    }
};
 
 
class VanillaMilkShake: public MilkShake
{
private:
    MilkShake *m_MilkShake;
public:
    VanillaMilkShake(MilkShake *baseMilkShake): m_MilkShake(baseMilkShake){}
 
    string Serve()
    {
        return m_MilkShake->Serve() + " decorated with Vanilla ";
    }
    float price()
    {
        return m_MilkShake->price() + 80;
    }
};
 
 
int main()
{
  MilkShake *baseMilkShake = new BaseMilkShake();
  cout << "Basic Milk shake \n";
  cout << baseMilkShake -> Serve() << endl;
  cout << baseMilkShake -> price() << endl;   
 
  MilkShake *decoratedMilkShake = new MangoMilkShake(baseMilkShake);
  cout << "Mango decorated Milk shake \n";
  cout << decoratedMilkShake -> Serve() << endl;
  cout << decoratedMilkShake -> price() << endl;   
     
  delete decoratedMilkShake;
 
  decoratedMilkShake = new VanillaMilkShake(baseMilkShake);
  cout << "Vanilla decorated Milk shake \n";
  cout << decoratedMilkShake -> Serve() << endl;
  cout << decoratedMilkShake -> price() << endl;   
 
 delete decoratedMilkShake;
 delete baseMilkShake;
 return 0;
}

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

While you could definitely eliminate the more abstract Decorator class in favour of inlining its members into the more concrete decorators, there are at least two benefits I can see to retaining it:

  1. If you so desired, you could restrict methods to accept or return decorated objects; for example, MilkShake *undecorate(MilkShakeDecorator *) is type-safe, but how would you do this without the intermediate type? While this might feel inane, consider that in a real world application, your types are not milkshakes, but potentially things like networking protocols. Being able to take a stack of protocols and slip one off could be quite a useful application.

  2. It fosters a better understanding of what’s going on. If I simply had class MangoMilkShake : MilkShake, my thought may be that it’s going to implement its behaviours on its own, i.e. may be fixed to a particular base flavour. By instead seeing that is a decorator, it gives me a better understanding of how the type may behave, i.e. it will adapt some other type to provide addition behaviours.

As with all opinion questions, you should take my answer with a grain of salt, as there can be arguments for both sides.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading