Decorator Pattern

As the name suggests, a Decorator "decorates" a class. The code is pretty similar to a container class. But the concept is different. A decorator is used when we want to add a lot more functionality to the given class - that does not make a case for inheritance.

Note that inheritance is used only when we have a genuine "Is a" relationship. When we just want to add more functionality, we should use a decorator. This essentially contains the original class object and adds more functionality to it. The calls are passed over to the contained class - perhaps with some more logic before and after it. The decorator can also have its own methods.

To elaborating again, that is exactly what we do with inheritance. But we should use decoration rather than inheritance when the extension does not merge well in the class hierarchy. For example, consider the hierarchy - Shape - Polygon - Quadrilateral - Rectangle - Square.

Now if we have a "Yellow Rectangle", it does not fit well in this hierarchy. The language does not prevent us from using inheritance here. But, the design principles do. Instead, here we should use a decorator class - Yellow Shape - that can have a hierarchy of its own. The Yellow Rectangle would contain an object of class Rectangle.

The Decorator pattern has four participants:

  • Component - Defines the interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent - Defines an object to which additional responsibilities can be attached.
  • Decorator - Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
  • ConcreteDecorator - Adds responsibilities to the component.