I am going through the book Head First Design Patterns and am specifically looking at the Starbuzz example for the Decorator
pattern.
I am having trouble understanding that what exactly is the need for CondimentDecorator
in the example provided. Why can't Mocha
simply extend Beverage
? What's the need for another layer of abstraction?`
public abstract class Beverage
{
String description = "Unknown beverage";
public String getDescription()
{
return description;
}
public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage
{
public abstract String getDescription();
}
public class Mocha extends CondimentDecorator
{
Beverage b;
public Mocha(Beverage b)
{
this.b=b;
}
public String getDescription()
{
return b.getDescription() + ", Mocha";
}
public double cost()
{
return .20 + b.cost();
}
}
Well, in the sample you posted it isin't that clear, but the abstract class usually takes care of the component encapsulation and the default method implementations are to delegate method calls to that component.
Therefore, when implementing concrete decorators, you would't have to override all methods if you don't need to.
e.g.
public abstract class CondimentDecorator extends Beverage {
Beverage beverageToDecorate;
public CondimentDecorator(Beverage beverageToDecorate) {
this.beverageToDecorate = beverageToDecorate;
}
public String getDescription() {
return beverageToDecorate.getDescription();
}
public double cost() {
return beverageToDecorate.cost();
}
}
Why can't Mocha simply extend Beverage? What's the need for another layer of abstraction?
The problem is how to deal with the combinations. Mocha
is only one variant, but what about Mocha + House Blend + Steam Milk, etc. There's a lovely image on p.81 of the design solution using only this "layer" which has so many classes inheriting from Beverage
that it's a "maintenance nightmare."
The CondimentDecorator
allows adding any number of combinations to your Beverage
through composition rather than inheritance.