Sometimes we need to extend an object functionality, a normal way we can do it statically by inheritance mechanism. This is not wrong, but in some situations it makes source code more complex as well. That is reason Decorator pattern, a way of extending functionality dynamically, was born.
According to GoF, Decorator pattern is one of the widely used structure patterns. This pattern dynamically changes the functionality of an existed object at runtime without impacting on the existing functionality of the other objects.
So, what is different between extending functionality dynamically from extending statically? Basically, to extend some functionalities of object by inheriting we have to implement codes to extend existing class and override those functions. And these works were done in compile time. In other words, we are creating a new class and the changes that we do will affects every objects of this class. Extending dynamically, on the other hand, provides a mechanism that allows us modify an existed object without any effect on other objects of the same class. And all works were executed in runtime.
Moreover, there are some situations that to use inherit will take lots of effort to write code. On the other hand, Decorator pattern saves you a tons of time to write code. Let consider a very popular sample from GoF books, sample about Pizza. Imagine a scenario where you are working in a Pizza shop, and your shop also baked tomato pizza and cheese pizza. After that you need to put some additional topping and combination of these topping because of customer’s choice, chicken and pepper for instance. Basically, you have to make these kinds of pizza: tomato-chicken pizza, tomato-pepper pizza, cheese-chicken pizza, cheese-pepper pizza, tomato-chicken-pepper pizza and cheese-chicken-pepper pizza. In this case, if you decide to use static extending, you have to create a lot of classes likes TomatoChickenPizza, TomatoPepperPizza, … It mean that the more number of combination of additional topping customer needs, the more class you do have to implement. On the other hand, Decorator pattern helps us decrease the number of extra-classes. In order to be clear, let take a look at its class diagram.
Following are participants of Decorator pattern:
Component: Common interface for objects that need additional functionalities at runtime.
ConcreteComponent: An implementation of Component interface that defines an object need additional functionalities at runtime.
Decorator: An abstract class that maintains a reference of component object and also implements component interface.
ConcreteDecorator: An implementation of Decorator, it implements additional functionalities on top of Component objects.
Now come back to above Pizza example, we are implementing the system as bellow. You can get the full source here.
IPizza interface is the Component in Decorator pattern, it has function doPizza() that shows appropriate pizza object.
TomatoPizza and ChickenPizza are implementations of IPizza. They provide specifically instances of classes that need to add extra-functionalities at runtime.
PizzaDecorator is heart of whole system. It maintains reference to an existing pizza that is an instance of TomatoPizza or ChickenPizza. This reference will be passed through its constructor, and it will be extended at runtime.
PepperDecorator and CheeseDecorator implement additional functionalities, in this situation PepperDecorator adds pepper to an existing pizza. This extra-feature is implemented in function addPepper().
OK, that is all we need to know about Decorator design pattern. In programming world, this pattern is applied widely, especially to work with stream in Java.