Decorator pattern: Why do we need an abstract decorator?

Viewed 11721

This question was asked already here, but rather than answering the specific question, descriptions of how the decorator pattern works were given instead. I'd like to ask it again because the answer is not immediately evident to me just by reading how the decorator pattern works (I've read the wikipedia article and the section in the book Head First Design Patterns).

Basically, I want to know why an abstract decorator class must be created which implements (or extends) some interface (or abstract class). Why can't all the new "decorated classes" simply implement (or extend) the base abstract object themselves (instead of extending the abstract decorator class)?

To make this more concrete I'll use the example from the design patterns book dealing with coffee beverages:

  • There is an abstract component class called Beverage
  • Simple beverage types such as HouseBlend simply extend Beverage
  • To decorate beverage, an abstract CondimentDecorator class is created which extends Beverage and has an instance of Beverage
  • Say we want to add a "milk" condiment, a class Milk is created which extends CondimentDecorator

I'd like to understand why we needed the CondimentDecorator class and why the class Milk couldn't have simply extended the Beverage class itself and been passed an instance of Beverage in its constructor.

Hopefully this is clear...if not I'd simply like to know why is the abstract decorator class necessary for this pattern? Thanks.

Edit: I tried to implement this, omitting the abstract decorator class, and it seems to still work. Is this abstract class present in all descriptions of this pattern simply because it provides a standard interface for all of the new decorated classes?

9 Answers

It enables the decoration of the base class independently with various decorators in different combinations without having to derive a class for each possible combination. For example, say you want your Beverage with milk and nutmeg. Using decorators based on the abstract decorator class, you merely wrap with with Milk and Nutmeg decorators. If it was derived from Beverage, you'd have to have a MilkWithNutmegBeverage class and a MilkBeverage class and a NutmegBeverage class. You can imagine how this explodes as the number of possible combinations increases. Using the abstract decorator implementation reduces this to just one decorator class implementation per decoration.

The base Decorator makes it easier to create additional decorators. Imagine that Beverage has dozens of abstract methods, or is an interface, say stir(), getTemperature(), drink(), pour() and the like. Then your decorators all have to implement these methods for no other reason than to delegate them to the wrapped beverage, and your MilkyBeverage and SpicyBeverage each have all those methods.

If instead you have a concrete BeverageDecorator class that extends or implements Beverage by simply delegating each call to the wrapped Beverage, subclasses can extend BeverageDecorator and only implement the methods they care about, leaving the base class to handle delegation.

This also protects you if the Beverage class (or interface) ever gains a new abstract method: all you need to do is add the method to the BeverageDecorator class. Without it, you would have to add that method to each and every Decorator you had created.

actually i also sometimes leave out this 'middle-man' abstraction (if you don't have many decorator combinations). it decouples more but also adds complexity. in my view the main idea behind decorating is wrapping interfaces inside their own implementations.

Related