Introduction
Kartoon Kompany approaches you for re-designing their application on the famous Kelvin and Hoppes comic strip!
A quick recap about Kelvin: he is a moody brat with an extremely wild and vivid imagination. His behavior and reactions are completely different and unpredictable, and is based on his current fantasy he has dreamed up. He thinks up imaginary worlds and situations, like a spaceman battling Zorgs, TracerBazooka – Film Noir detective, imagines he is a T-rex, so on and so forth.
This is their current design:
class Kelvin
{
public:
virtual void MisBehave()
{
std::cout<< "Hi, I am Kelvin the Great!\n";
}
};
class SpacemanDecorator: public Kelvin
{
public:
virtual void MisBehave()
{
std::cout<< "The fearless Spaceman Kpiff battles with the Zork!!!\n";
}
};
class DinoDecorator: public Kelvin
{
public:
virtual void MisBehave()
{
std::cout<< "Kelvin the terrible T-Rex runs rampant in Jurassic park!\n";
}
};
class TracerBazookaDecorator: public Kelvin
{
public:
virtual void MisBehave()
{
std::cout<< "TracerBazooka: Here's looking at you kid.\n";
}
};
Now, Kartoon Kompany has a problem: for the next comic strip, they want to combine a T-Rex episode and a Spaceman episode in one strip. Fans go wild with anticipation.
How do we address this? Simple, let's create a DinoSpaceman
behavior class where Kelvin acts accordingly, right?
Do you see how easily this could explode into a plethora of subclasses? What about a T-Rex-Spaceman episode? What about a Tracer-TRex episode? Think sub-class nuclear explosion. And we are not even talking of adding new classes like WithSusie
, SnowBallFights
, SantaLetters
, etc.
This is the problem Kartoon Kompany approaches you with. How do you solve this design issue?
Inheritance, though powerful, is not the panacea for Kartoon Kompany’s woes. The problem with the current design is, because all behaviors are defined in sub-classes, we need to keep adding lots of sub-classes, and that is especially difficult considering Kelvin’s unimaginable imagination.
Enter Decorator Design Pattern (on an F-16 figher jet, with guns blazing)
Okay, so inheritance is out. The problem is that we are trying to define all of Kelvin’s behavior at compile time. Wouldn’t it be great if we could specify Kelvin’s behavior at run-time? Then we don’t have to sub-class, but could use composition at run-time to define Kelvin’s reactions (author’s note: don’t worry if this doesn’t make sense now, read on).
The Decorator Design Pattern does that for us! Short and sweet, Decorator does following:
- Adds behavior to a class dynamically, at run-time. This is in contrast to inheritance, which binds behavior statically, i.e., at compile time.
- Is an alternative to sub-classing.
Enough theory, let’s take a plunge and see how the Decorator Design Pattern helps Kelvin.
Apply the simplest of Design Principles: encapsulate and separate what varies. Since the combination of various Kelvin imagination\behavior varies, let's take them out of the Kelvin class hierarchy. I.e., TRex
, Spaceman
, TracerBazooka
should no longer be derived classes of the Kelvin
superclass. Since the function MisBehave()
is common, let's create a common base class, which will be our brand new decorator base class!
class KelvinDecorator: public Kelvin
{
public:
KelvinDecorator(Kelvin *kelvinArgument): KelvinComponent(kelvinArgument)
{ }
virtual void MisBehave()
{
kelvinComponent->MisBehave();
}
private:
Kelvin *kelvinComponent;
};
Now, with this base decorator as the super\base class, we create the Kelvin Decorator specific classes:
class SpacemanDecorator: public KelvinDecorator
{
public:
SpacemanDecorator (Kelvin *kelvin): KelvinDecorator(kelvin)
{ }
virtual void MisBehave()
{
KelvinDecorator::MisBehave();
std::cout<< "The fearless Spaceman Kpiff battles with the Zork!!!\n";
}
};
class DinoDecorator: public KelvinDecorator
{
public:
DinoDecorator (Kelvin *kelvin): KelvinDecorator(kelvin)
{ }
virtual void MisBehave()
{
KelvinDecorator::MisBehave();
std::cout<< "Kelvin the terrible T-Rex runs rampant in Jurassic park!\n";
}
};
class TracerBazookaDecorator: public KelvinDecorator
{
public:
TracerBazookaDecorator (Kelvin *kelvin): KelvinDecorator(kelvin)
{ }
virtual void MisBehave()
{
KelvinDecorator::MisBehave();
std::cout<< "TracerBazooka: Here's looking at you kid.\n";
}
};
That’s it! You’ve implemented the Decorator Design Pattern! Now, we let the beauty of basic OOPS do the work!
Kelvin *mainComponent = new Kelvin();
KelvinDecorator *pAddedFunctionality = new SpacemanDecorator(
new DinoDecorator (
new TracerBazookaDecorator(mainComponent) ) );
pAddedFunctionality->MisBehave();
We’ve done nothing but add one layer of Kelvin on top of another. KelvinDecorator
does its job and hands the baton to another KelvinDecorator
, which in turn hands it to another, and so on and so forth. And, we did all this without modifying the main component class Kelvin
!

Congratulations, you’ve just learnt another design principle: Open-Close principle. Which simply means a class should be closed for modification, but open for extension or change.
For our example, the class Kelvin
is closed for modification – we never had to modify the Kelvin
class. But we still were able to alter Kelvin
’s behavior through decorators (thus we made it open for extension).
And we did this by adding new layers of KelvinDecorator
at run-time!
And last but not least, the output of our program:

Things work great. Now it is easy to add and combine any of Kelvin
’s behaviors with very little design change, and more importantly, all this with no change in the Kelvin
class!
Change in Requirement
Let's see how easy Decorator makes it for handling change\adding new behavior.
Kartoon Kompany wants a new behavior for Kelvin for next week’s comic strip: an episode with Susie.
Our design now makes it very easy to add new behavior. If you need a new WithSusieDecorator
, just add the new subclass decorator (write a WithSusieDecorator
and derive it from KelvinDecorator
) to get the desired functionality. In fact, do try doing this as an assignment to see how easy it is to add a new decorator with very little change to the existing design and code. Try outputting the text “GROSS! Let's hit Susie D with 1,000 snowballs!!”
You also need to create a new WithSusieDecorator()
when creating layers of Kelvin Decorators in our client function (you could use a Factory for this, but that is a different design pattern for a different day!).
That’s it! How easily we have added new behavior at runtime. Can you imagine the pain and amount of changes to make if we still had used the static-subclassing way?
Kartoon Kompany is screaming with pleasure at how easy and resilient our new design is to change!
They’re so happy that they plan to introduce you in next week’s strip and let Kelvin hit you with 1,000 snowballs!
A change like that is now easy and systematic, thanks to the Decorator Design Pattern, but whether you want to put up with Kelvin’s antics is up to you!
Decorator Design Pattern Considerations
Okay, now that you’ve understood the Decorator Design Pattern, there are a few more things you should be aware of:
- Don’t derive
KelvinDecorator
directly from Kelvin
. You should take out the common, required interfaces and put them as a base class (Character
?), and have Kelvin
derive from the Character
superclass. KelvinDecorator
also derives from the Character
superclass. This makes the decorator light-weight, and doesn’t hog it with all unnecessary functionality from Kelvin
’s class. - While decorators are great, they have their disadvantages:
- It's very difficult for a developer who doesn’t know this pattern to understand a code written with decorators. You are better than that poor dude as you now know about decorators!
- Decorators tend to add a lot of small classes, but that’s something you have to live with.
- Any client code that relies on RTTI (i.e., if the client checks for a derived class object type, or in simpler words, whether this is a
Kelvin
object) won't work for decorators. This is because you do not know which decorator layer object we have with us. It could be Spaceman, TRex, Tracer.
- Go read the Decorator Design Pattern from GoF book now! This article was intended to make things easy to understand, and to whet your appetite for the GoF chapter on decorators. Search for "Design Patterns: Elements of Reusable Object-Oriented Software", or the GoF book as it is affectionately called.