Decorator: The Best Pattern
There is a widely known pattern called the Decorator. Some developers use it properly, some developers use it wrong, but most do not use it at all. I want to explain what the decorator is and when and how you have to use it.
What is the Decorator?
If you want to slightly change the behavior of an object without changing its interface, then the Decorator is your best option. The idea is the following: you can wrap an object into an additional layer with the same interface, change the behavior of some methods, and proxy all other calls. This new layer is called the decorator. Here is the UML diagram that describes the decorator’s structure.
Do you not understand it? No worries, I will explain it to you. First, think about Russian dolls put inside each other. Then imagine that they can talk to each other: the biggest one to the smaller one, the smaller one to the even smaller one, and so on. This communication can happen only in one direction: from the big doll to the small one, but not vice versa. It works with way because each doll can only know what is inside it and talk to the smaller one but not to the bigger one that keeps it inside.
Basically, this is the decoration principle in a nutshell. You have many objects with the same interface (identical dolls), each decorator object (big doll) may contain another object (small doll) and can call its methods (big doll talks to small doll) but the nested object is not aware of the decorator (small doll can not talk to the big doll). Here is a better diagram that explains how the nested object is stored inside the decorator object.
But why somebody may want to have nested objects with the same interface?
Pros and Cons
The decorator is one of the patterns that ensure the extendability of the original object without breaking an interface. What does it mean? You can change the behavior of the application without breaking it! Cool, right?
Another advantage of the decorator is that you can create as many decorators for the same object as you want, and all of them can work together without any issues. It’s like you have multiple Russian dolls one inside the other, and they can talk to each other from the biggest to the smallest without any trouble.
The decorator is also superior over regular inheritance as decorators must not be aware of each other while the child class must always be aware of the parent. This feature makes decorators perfect for the 3rd party extensions or plugins because they can work together without knowing each other. The principle that describes the superiority of decoration over inheritance is widely known as composition over inheritance.
Wait, is it the perfect pattern in the world? Why is it not used for every class? Now I can tell you several disadvantages and traits of it. First, you have to use it only if you are extending a defined domain model. Second, the decorator can not change the interface and the purpose of the class, only its behavior. Third, decoration has to do implemented very carefully to maintain compatibility with existing functionality and not break if there are more decorators.
Now you know what the decorator is, when you need to use it, and when it is better to find something else. It is a big step forward to becoming a good developer and professional software engineer!