jeudi 29 décembre 2016

Functionality inside abstract decorator class instead of decorators

I'm currently reading the book Head First Design Patterns and in the Decorator chapter there is the following example:

Example diagram

In the book the CondimentDecorator class is described as an abstract decorator. Here is the code example:

public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

So basically inside is only an abstract method which forces all subclasses to override the getDescription() method from Beverage class.

And here is the code example of a Mocha class as the decorator.

public class Mocha extends CondimentDecorator {
    Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }

    public double cost() {
        return .20 + beverage.cost();
    }
}

The other decorators (Whip class, Soy class...) have exactly the same code, except for the hardcoded cost number (.20) and name (", Mocha").

We then use this decorator pattern by passing the previous object into the new decorator.

Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
beverage = new Mocha(beverage);
beverage = new Whip(beverage);

My question is, why not simply move the duplicated functionality from decorators to abstract decorator? Here is how I refactored the example.

Abstract decorator:

public abstract class CondimentDecorator extends Beverage {
    private Beverage beverage;

    protected CondimentDecorator(Beverage previousBeverage) {
        this.beverage = previousBeverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", " + getAdditionName();
    }

    @Override
    public double cost() {
        return beverage.cost() + getAdditionCost();
    }

    public abstract String getAdditionName();
    public abstract double getAdditionCost();
}

Decorator code:

public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getAdditionName() {
        return "Mocha";
    }

    @Override
    public double getAdditionCost() {
        return 0.20;
    }
}

Now for every new decorator I create I'm forced to provide the previous beverage object via constructor for the superclass constructor and I need to override methods which only return the unique values for the specific decorator.

Is this code OK? Or does it completely change the point of Decorator pattern if I have functionality in the abstract decorator?

Aucun commentaire:

Enregistrer un commentaire