Hey! Did you ever want to add some functionality to an already existing method, but you feel that monkey patching or inheritance are not probably the best way to do it? In today’s post I will show you how you can achieve that in an elegant way. Did you guess it? Today we are going to talk about Decorator in Ruby, but first, let’s see the alternatives and why they might not be the best solution for our problem.

Inheritance

Many people would advocate for using inheritance, a typical way to go is “make your class inherit from the already existing class we want to extend and just redefine your class”, but stop… is your class really and specialization of the already existing one? On top of that, in many languages like Ruby you can only have one parent class, so that kind of dependency is limited to just one, you should choose it wisely!

Monkey patching

Other people will just tell you, “Monkey patch that class, create an alias for the old method, override it and add your thing”. But then I would tell you, what if that class changes? How can you be sure that your monkey patch keeps working? What if a third party gem also decides to monkey patch that class and override that same method? As you can see there are many flaws to that approach.

The Decorator pattern

The Gang of Four pattern

The decorator pattern is not a brand new, shiny, fancy thing. In fact, it has been around for a while. It was already described in the famous “Design Patterns” book from the Gang of Four in 1995. On the intent of the decorator pattern they said:

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

But how can this help us?

The Ruby way

In this post we will not build the typical structure you would see for other languages like Java or C++ based on Components, ConcreteComponents, Decorators and inheritance relations, we will instead see how this is done in Ruby.

To our luck in Ruby we can mix in modules to existing objects or even classes. Let’s see it with an example.

Imagine we have a class that models a King in a role game which has some equipment:

If we want to add a shield to our King, instead of defining a class KingWithShield we can instead do it with a decorator like this:

Then imagine we have two Kings, Aragorn and Arthur, and we want to give Arthur a shield, while Aragorn has enough with his sword because he is very brave:

If we later decide we need to have Armors also in our game we can do it with a decorator too:

And then because Kings are very important let’s give an armor to both of them this time so that they are well protected:

As you can see, it is really easy to dynamically add functionalities to already existing objects, and even to classes, although we will not see that today. Instead, I will leave it to you as an exercise or if you want me to do it, just leave a comment down below.

See you next time!

Bibliography

One Response