This article is created in continuation to a series of easy patterns description, and describes structural pattern attaching additional responsibilities to an object dynamically.

Currently you can find articles for such patterns:

Creational patterns:

Structural patterns:

Behavioral patterns:

The main essence

In some sources, Decorator pattern and Adapter pattern are named as Wrapper, so it should be clarified which pattern it is. It works perfectly well if you need to add some extra functionality not to the entire class itself, but for some concrete instance.

So what is the main difference between Decorator and Adapter? For Adapter pattern, it’s typical when you extend Adaptee class or create a new class with rewritten methods in the way it conforms to Target class (see details in Adapter pattern article). In Decorator case the purpose is simple — add a new functionality to concrete object instance dynamically. The decorator forwards requests to the component and may perform additional actions.

This pattern includes two main roles:

component — defines an object to which additional responsibilities can be attached

— defines an object to which additional responsibilities can be attached decorator — adds functionality to the component

Example of use

This is a classical example with passing a class instance to decorator to extend some functionality.

In this example, we’re building a base airplane and its modifications (transatlantic and jet). Decorators use base methods of the passed instance to extend it in a way that’s needed. JetPlane extends maximum speed of the base airplane and TransatlanticPlane extends its maximum distance.

Profit

This pattern helps to add desired functionality to an individual object dynamically and transparently without affecting other objects.

It’s also nice to use it to separate functionality in a transparent way (you can see what each decorator is used for in relation to the base object functionality).

Decorator forwards requests to its Component object. It may optionally perform additional operations before and after forwarding the request. This adds much more flexibility in adding extra functionality.

Weak places

Decorators and components aren't identical items. A decorator acts as a transparent enclosure. So you shouldn't rely on object identity when you use decorators.

This pattern forces you to have a lot of small objects in the system. These small objects only differ in the way they’re interconnected. Even more, it’s easy to decorate object accidentally several times and get an unexpected result. With classical inheritance, it’s harder to do such things. So, for those who understand them, it’s easy to customize such systems, all you need is to understand what decorators are used in the system and for what purpose.

Conclusion

If you found this article helpful, please hit the 👏 button and feel free to comment below!