关于java:抽象装饰器类中的功能而不是装饰器

Functionality inside abstract decorator class instead of decorators

我目前正在阅读《Head First Design Patterns》一书,在"Decorator"一章中有以下示例:

Example diagram

在书中,conditionmentDecorator类被描述为一个abstract decorator。下面是代码示例:

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

因此,基本上内部只是一个抽象方法,它强制所有子类从饮料类重写getDescription()方法。

这里是一个mocha类的代码示例,作为decorator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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();
    }
}

其他装修商(鞭子类,大豆类…)有完全相同的代码,除了硬编码的成本数字(.20)和名称(",摩卡")。

然后,我们通过将前一个对象传递给新的装饰器来使用这个装饰器模式。

1
2
3
4
Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
beverage = new Mocha(beverage);
beverage = new Whip(beverage);

我的问题是,为什么不简单地将复制的功能从装饰器移到抽象装饰器?下面是我如何重构示例。

抽象装饰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
}

装饰代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        super(beverage);
    }

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

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

现在,对于我创建的每个新的装饰器,我都必须通过超类构造函数的构造函数提供以前的饮料对象,并且我需要重写仅返回特定装饰器的唯一值的方法。

这个代码可以吗?或者,如果我在抽象装饰器中具有功能,它是否完全改变了装饰器模式的要点?


这个代码很好。经常阅读课本(?)在他们的示例中呈现不太完美的代码,这样他们就可以专注于一个特定的概念(在本例中是装饰师),而不必关注其他细节。事实上,你找到了一种改进这本书代码的方法,这表明你实际上已经很好地理解了这个概念,能够智能地使用它,而不仅仅是从引用中复制粘贴。


我认为答案是你不想在一节课上做两件事。

CondimentDecorator做了一件事:连接两个饮料。它真的应该被命名为"MixDecorator"

当你把调料的共同方面分解成代码时,你需要创建另一个类,可以称之为"命名调料",并将名称和成本放在里面。