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.

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.

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!

//derive from Kelvin so that interface of decorator is same.
//This makes life easy on the client (caller) side
//this will be our base decorator class. We are adding
//new behavior to Kelvin thru composition
class KelvinDecorator: public Kelvin
{
public:
//ctor taking in component to decorate (i.e. Kelvin) as argument.
//We need a Kelvin in order to decorate\add new behavior,
//there is no KelvinDecorator without Kelvin!
KelvinDecorator(Kelvin *kelvinArgument): KelvinComponent(kelvinArgument)
{ }
//overload common interface from Kelvin
virtualvoid MisBehave()
{
//just ask kelvin to misbehave! The wonder of virtual keyword
//and polymorpishm will call correct derived class,
//either Decorator or main component
kelvinComponent->MisBehave();
}
private:
//Kelvin component, which we need to decorate
Kelvin *kelvinComponent;
};

Now, with this base decorator as the super\base class, we create the Kelvin Decorator specific classes:

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.

My vote of 5... But one suggestion in next articles, please relate the UML diagram like in this case which is the concrete decorator, concrete component. Can you please state them I need to verify my understanding

If you look at the attached code sample, there indeed are virtual dtors.When pasting selective code in an article, I believe the foucs should be on main topic of disucssion. This is why I focussed on decorators in article's code, but in attachment, there is proper code with virtual dtors, lot more code comments, etc. Do take a look!

A more detailed discussion as to what makes the pattern tick in C++ terms would have been nice - where for instance you'd use it over strategy (e.g. it can be quicker to convert an existing class hierarchy into a concrete class and a bunch of decorators than have to intrusively hack out a strategy) and how it falls out (or doesn't) and/or complements techniques like test driven development.