0

I am trying to understand better the decorator pattern. I have read an article with an example implementation in java and of course, GoF book.

Do I always need an abstract parent for the decorator?

For instance, in the example I have an abstract ChistmasTree and its implementation, and an abstract TreeDecorator inheriting from ChrimasTree. The TreeDecorator has an abstract decorator() method. Let's assume I have a totally unique override of decorate() for each and every decorator implementation: TreeTopper, Tinsel, Garland, and BubbleLights, simple needs to implement ChristmasTree. Why create an additional compilation unit under these circumstances?

  • With decorator, you are not going to have some generic "decorate()" method; you are going to have components that do something, and share a certain set of public methods and properties (an abstract interface). The key idea of decorators is that they add optional functionality in a transparent way - i.e., code that calls it doesn't even know there's a decorator in between (or several of them). To achieve that, a decorator must have the same abstract interface. That's crucial. 1/2 – Filip Milovanović Jan 14 at 16:03
  • Other than that, it's just a wrapper over any other component that implements that same interface. The reason that there's an abstract Decorator base class is that all decorators need to store the wrapped component somewhere, so they share that bit of their implementation. 2/2 – Filip Milovanović Jan 14 at 16:03
  • P.S. If it's still unclear, do a simple exercise; create a class that implements some interface (with a couple of methods - try to come up with something meaningful, but simple). Then write some code that calls those methods through the interface (through a variable of the interface type). Now create two decorators, but do it your way, without having a base class for them - wrap them over your example component without changing the code that actually calls the interface methods from before. It can be done, but you'll encounter some repetition. – Filip Milovanović Jan 14 at 16:09
3

In the GoF you will see that:

  • the Decorator inherits from Component in order to offer the same interface
  • the Decorator uses composition of a Component object in order to be able to dynamically decorate/undecorate a component.
  • the Decorator therefore implements all the methods of the Component interface by forwarding the call to the component.

In other words, theDecorator is not just an interface: it’s a real class that is responsible of holding the component reference and forward the calls to the base-class methods. In principle, all its methods should be implemented. It is therefore not “abstract” in the sense that there would be missing implementation details, but only conceptually abstract, meaning that it’s supposed to be extended by concrete decorators.

If the enrichment is simple, there is indeed no need to add this abstract decorator class. The GoF points this out in the discussion about implementation issues:

There’s no need to define an abstract Decorator class when you only need to add one responsibility. That’s often the case when you’re dealing with an existing class hierarchy rather than designing a new one. In that case, you can merge Decorator’s responsibility for forwarding requests to the component into the ConcreteDecorator.

I nevertheless would be reluctant to get rid of this middleman, especially if there could be a lot of method-calls to forward (i.e. base class methods that are not supposed to be changed by a decorator): the abstract decorator prevents a lot of repetitions of boilerplate code in the concrete decorators.

Minor remark: The example on which you work is somewhat confusing, since the component itself has adecorate() method, which could mislead to think that this has something to do with the decorator. In addition, despite the many concrete decorators, it misses the opportunity to show that new responsibilities could also be added to a decorator.

Not the answer you're looking for? Browse other questions tagged or ask your own question.