Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator Pattern : Why do we need an abstract decorator?

I am having difficulty understanding the following implementation advice from Erich Gamma's book Design Patterns regarding Decorator pattern.

Omitting the abstract Decorator class There's no need to define an abstract Decorator class when you only need to add one responsibility.

I don't see why abstract Decorator class is required at all? Why can't all decorators simply implement/inherit directly IComponent/Component?

like image 341
EagerToLearn Avatar asked Jan 31 '17 18:01

EagerToLearn


2 Answers

A decorator adds some functionality to some other classes. He forwards all messages for the old functionality to the decorated class. The new functionality is handled by the decorator itself. If there a more than one kind of new functionality to add than the code to forward the old functionality to the decorated class is placed in more than one class. That is why an abstract decorator is used.

Example: enter image description here

In the example above we want to derocate some classes from the IComponent hierarchy with either functionality A oder functionality B. The forwarding code for "someFunctionality()" would be in both classes. So we extract an abstract decorator class (avoid duplication). The only code in the derived decorators is now the functionality to be added plus calling the method of the superclass. This is important, because if the logic of the forwarding changes you have to change only the superclasses method. You can decorate FirstDerived and SecondDerived with the functionality A or B.

If you want to decorate the existing classes with no more than one functionality, you don't have to extract the forwarding of "someFunctionality", because there is only one decorator where this forwarding code is placed in.

Example: enter image description here

Gamma's implementation hint is about omitting the abstract decorator class which's only purpose is to forward the functionality of the ClassHierarchy so that in the concrete decorators is only the code that is important to add its new functionality.

I recommend you to start without the abstract decorator. But if you add a second decorator than you have to remove the duplicated code and thus extract the abstract class during your refactoring.

like image 80
Janis Avatar answered Sep 19 '22 05:09

Janis


I don't see why abstract Decorator class is required at all? Why can't all decorators simply implement/inherit directly IComponent/Component?

The purpose of the abstract class in the Decorator pattern is to eliminate code duplication. The crux of the Decorator pattern is to allow you to wrap an existing Component with new responsibilities. This wrapping is done by creating a new class that IS-A component and HAS-A component :

public class Decorator implements Component { 
    private Component component;

    public Decorator(Component component) { this.component = component; }
}

Imagine that you introduce two more decorators. You would now have to implement similar code in both your new decorators. The abstract decorator can help you solve exactly this problem. By moving the above code to an abstract class, all your concrete decorators can inherit from it and avoid the need to re-implement the decorator skeleton manually.

I understand that the Decorator in the above example doesn't do much; however, imagine a situation where you want to disallow further decoration based on some condition. For example, don't allow any more toppings on a Pizza if the cost will exceed 15$. The abstract decorator can take care of this by calling the getCost function on the component in the constructor. This will result in a call to all the getCost function of all the decorators and give you a final cost. If getCost()>15, the application can inform the user that the cost cannot exceed 15$. Such code reuse is the real motivation behind the abstract decorator class.

like image 45
Chetan Kinger Avatar answered Sep 20 '22 05:09

Chetan Kinger