Decorator Pattern? What That’s All About?

Eugenio Carocci
Geek Culture
Published in
4 min readDec 7, 2022

--

Photo by Christopher Burns on Unsplash

I remember when I was attending software engineering course back at the university some years ago (quite a few, time fliiiiies), it was a spring afternoon and I was quite tired due to some kind of heavy lunch (you know, we italians, do like to eat a lot when it comes to lunch).

At some point the professor went through his presentation and best guess about my thoughts is “oh my god this is boring, when is it going to finish?”.

Lesson was about the Decorator design pattern from the Gang of Four.

Fast forward to today, in my current job I use this pattern regularly to create flexible, extensible, easy to test and all the other good adjectives solution.

So, the goal of this article is to share with you why you should know this pattern and how you could benefit from it :)

So what is this Decorator design pattern?

In object-oriented programming, the decorator is a design pattern that allows behaviour to be added to an individual object, dynamically, without affecting the behaviour of other objects from the same class.

This one allows functionality to be divided between classes with unique areas of concern. Decorator use can be more efficient than subclassing, because an object’s behaviour can be augmented without defining an entirely new object.

If you want to know more about this one I suggest to either read the Decorator chapter in the GoF design pattern book or check out the Wikipedia article.

A report generation problem

So, recently I had to face a new challenge at work where I needed to create multiple reports to show customers some preeecious data.

Obviously, when you need to show data to user you have to:

  • Check if the user requesting it is authorized to do so
  • Check if it is needed to show only a subset of the requested data
  • Check if the request is valid and all the required information are provided

And the list could go on and on depending on your use-case.

And to demonstrate that software development is an always changing process, along the way, product team asked for a way to provide a cached version of the report but only if user permissions were not changed between the storage of the report in cache and the request time.

Naive solution

At first I started to write these reports one-by-one in a pretty independent manner, meaning that, I was slowly but steadily duplicating my code to take into account all the business necessities.

The solution wasn’t that bad, it was something like this

Basically, for each report I defined one request, generator and response object with the simple factory responsible for retrieving the correct generator based on the request.

The business logic was all located inside the generator class that was responsible for taking into account all the business requirements.

It was nice since and easily extensible, if you needed to work on a specific report you were able to do that on a single class and it was easily testable.

But, the more reports I was creating the more I was getting to the point that I could have improved something a little bit by being more mindful about my approach, especially, I thought that I could have find a better way to handle some of the common business requirements.

Solution with the Decorator design pattern

Soooo, here’s what I did to improve my solution by taking advantage of the Decorator design pattern :)

Basically the idea is to define multiple decorator classes, each one with a very specific responsibility: one to retrieve what the user can and can’t access, one to check if there’s already a cached version of the report and so on.

The beauty of having decorators with just one clear responsibility is that they are easy to be developed, tested and composed together. Is this ringing some bell such as single responsibility or open-closed principle? 👀

Each generator will work on the request object and will execute its thing, for instance:

  • PermissionDecorator will remove item from the request that can not be accessed by the user
  • CacheDecorator will check if the same request has already been processed and the response it’s available in cache, if that’s the case no more processing will be done and the cached response will be provided back to the client

Final Thoughts

I hope that this article helped some of you figure out the potential of this design pattern when you have to deal with similar problems!

Thanks for reading and feel free to add comments about your experiences :)

All the diagrams have been created using https://plantuml.com/

--

--