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:

示例图

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?


This code is just fine. Text books often(?) present less-than-perfect code in their examples so they can concentrate on a specific concept (in this case - decorators) and not draw attention to other details. The fact that you found a way to improve the book's code shows that you actually understood the concept well enough to intelligently use it, not just copy-paste from a reference.


I think the answer is that you don't want to do two things in one class.

The CondimentDecorator does one thing: connects 2 beverages. It really should be named "MixDecorator"

When you factor out the common aspects of the condiments as coded, you need to create another class, may be call it "NamedPricedCondiment" and place the name and the cost in there.

链接地址: http://www.djcxy.com/p/32010.html

上一篇: 如何在TextView中显示HTML?

下一篇: 抽象装饰器类中的功能而不是装饰器