What
Decorator design pattern is a type of structural pattern. This pattern is mainly used for assigning more features to an existing object dynamically. This means, the use of Decorator shall not impact other existing objects of the same class.
In other words, Decorator pattern also act as Wrapper over an existing object with additional features.
Why
Firstly, let us try to understand the need of Decorator pattern by taking an example application which displays computer components.
Here, in this application, we are having a computer class which is base class. Consequently, two classes, with additional features basic computer and smart computer will inherit from this Base.
Basic computer is having below features :
- Basic Screen
- Single CPU
- Basic keyboard
Smart computer is having below features :
- Touch Screen
- Dual CPU
- BT keyboard
Below is the sample code for above application :
#include<iostream> //main header
using namespace std;//for namespace
class Computer
{
public:
virtual void displayComponents()= 0;
};
class BasicComputer: public Computer
{
public :
void displayComponents()
{
cout << " Basic screen "<<" Single CPU "
<<"Basic keyboard"<<endl;
}
};
class SmartComputer: public Computer
{
public :
void displayComponents()
{
cout <<"SmartComputer is having below components"
<<endl;
cout << " Touch screen "<<" Dual CPU "
<<"BT keyboard"<<endl;
}
};
int main()
{
SmartComputer s1;
s1.displayComponents();
}
Suppose, now we have audio component also available for both Basic and Smart Computer.
Two ways of implementing this change without Decorator Design Pattern
Update existing BasicComputer & SmartComputer classes
Drawback of above approach is that it will impact behavior with existing clients. It may happen that we may need to support BasicComputer and SmartComputer without audio also.
Subclass new classes as BasicAudioComputer and SmartAudioComputer
Drawback of this approach is that in this way code will keep increasing. Therefore, in future, when more components added it will become difficult to manage.
Below is the sample code with subclass approach:
#include<iostream> //main header
using namespace std; //for namespace
class Computer
{
public:
virtual void displayComponents()=0;
};
class BasicComputer: public Computer
{
public :
void displayComponents()
{
cout << " Basic screen "<<" Single CPU "
<<"Basic keyboard"<<endl;
}
};
class BasicAudioComputer: public Computer
{
public :
void displayComponents()
{
cout << " Basic screen "<<" Single CPU "
<<"Basic keyboard"<<" Audio"<<endl;
}
};
class SmartComputer: public Computer
{
public :
void displayComponents()
{
cout<<"SmartComputer is having below components"
<<endl;
cout<< " Touch screen "<<" Dual CPU "
<<"BT keyboard"<<endl;
}
};
class SmartAudioComputer: public Computer
{
public :
void displayComponents()
{
cout<<"SmartComputer is having below componentes"
<<endl;
cout<< " Touch screen "<<" Dual CPU "
<<"BT keyboard"<<" Audio"<< endl;
}
};
int main()
{
SmartComputer s1;
s1.displayComponents();
SmartAudioComputer s2;
s2.displayComponents();
}
In summary, we have seen issues with above approaches. Basically, some classes are difficult to extend and some are difficult to manage.
In short, if we have situation where we need to retain existing object and also to attach new features Decorator pattern is the best fit.
How
Lets try to update above application with Decorator pattern.
Decorator is also known as wrapper over existing object. Consequently, we need to follow below rules for updating above application with Decorator:
Create a wrapper Decorator class which will take responsibility of attaching new features.
Firstly, create AddComponent as Decorator wrapper class for attaching new features. We also need to derive it from computer so that it is must to implement display component interface.
class AddComponent: public Computer
{
public:
void addComponent( string s1);
}
Embed existing class object inside Decorator class
So that it must add new feature and delegate its responsibility also.
class AddComponent: public Computer
{
private:
computer *c1;
public:
AddComponent(Computer *c)
void addComponenent( string s1)=0;
};
Create new classes by deriving from Decorator class
Derive all added features from AddComponent so that no impact on existing Computer class.
class AddComponent
{
};
class AddAudioComponent: public AddComponent
{
};
Below is the class diagram for above application

Example code using Decorator Design Pattern
Below is updated application with audio support with Decorator pattern:
#include<iostream> //main header
using namespace std;//for namespace
class Computer
{
public:
virtual void displayComponents()=0;
};
class BasicComputer: public Computer
{
public :
void displayComponents()
{
cout<< " Basic screen "<<" Single CPU "
<<"Basic keyboard"<<endl;
}
};
class SmartComputer: public Computer
{
public :
void displayComponents()
{
cout<<"SmartComputer is having below componentes"
<<endl;
cout<< " Touch screen "<<" Dual CPU "
<<"BT keyboard"<<endl;
}
};
class AddComponent: public Computer
{
protected:
Computer *m_computer;
public:
AddComponent(Computer *c1):m_computer(c1)
{ }
virtual void displayComponents()=0;
};
class AddAudioComponent: public AddComponent
{
public:
AddAudioComponent(Computer *c1):AddComponent(c1)
{ }
void displayComponents()
{
m_computer->displayComponents();
cout<<" Audio "<<endl;
}
~AddAudioComponent()
{
delete m_computer;
}
};
int main()
{
AddAudioComponent s1(new SmartComputer);
s1.displayComponents();
}
As seen above, with Decorator pattern, we can easily extend features without impacting existing class. Therefore, in future, if we need to support more add on features just subclass from AddComponent.
Pros & Cons of Decorator Design Pattern
Pros
- Firstly, it is easy to extend
- Secondly, it is easy to maintain
- Finally, it does not impact existing features or class.
Cons
- Complex design due to one more hierarchy.
- In conclusion, it is difficult to test all combinations of decorator classes
Main Funda: Decorator design patters adds new features to object dynamically.