Decorator Design Pattern: Structural Patterns

Share the Article

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

Decorator Design pattern UML diagram

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.

Advanced C++ Topics

Abstract Factory Design Pattern
Singleton Design Pattern
Factory Method Design Pattern
Builder Design Pattern
Adapter Design Pattern
Prototype Design Pattern
Facade Design Pattern
Bridge Design Pattern
Composite Design Pattern

Share the Article

Leave a Reply

Your email address will not be published. Required fields are marked *