我目前正在阅读《Head First Design Patterns》一书,在"Decorator"一章中有以下示例:
在书中,conditionmentDecorator类被描述为一个abstract decorator。下面是代码示例:
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
因此,基本上内部只是一个抽象方法,它强制所有子类从饮料类重写getDescription()方法。
这里是一个mocha类的代码示例,作为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();
}
}
其他装修商(鞭子类,大豆类…)有完全相同的代码,除了硬编码的成本数字(.20)和名称(",摩卡")。
然后,我们通过将前一个对象传递给新的装饰器来使用这个装饰器模式。
Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
我的问题是,为什么不简单地将复制的功能从装饰器移到抽象装饰器?下面是我如何重构示例。
抽象装饰:
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();
}
装饰代码:
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getAdditionName() {
return"Mocha";
}
@Override
public double getAdditionCost() {
return 0.20;
}
}
现在,对于我创建的每个新的装饰器,我都必须通过超类构造函数的构造函数提供以前的饮料对象,并且我需要重写仅返回特定装饰器的唯一值的方法。
这个代码可以吗?或者,如果我在抽象装饰器中具有功能,它是否完全改变了装饰器模式的要点?
您本质上是在问,如果您对decorator模式的实现进行了更改,那么您是否在改变它的使用点。相反,问问——装饰图案的意义是什么?如果你摸索的话,你会发现你仍然有饮料装饰师,不管有没有你的编辑。
这个代码很好。经常阅读课本(?)在他们的示例中呈现不太完美的代码,这样他们就可以专注于一个特定的概念(在本例中是装饰师),而不必关注其他细节。事实上,你找到了一种改进这本书代码的方法,这表明你实际上已经很好地理解了这个概念,能够智能地使用它,而不仅仅是从引用中复制粘贴。
我认为答案是你不想在一节课上做两件事。
CondimentDecorator做了一件事:连接两个饮料。它真的应该被命名为"MixDecorator"
当你把调料的共同方面分解成代码时,你需要创建另一个类,可以称之为"命名调料",并将名称和成本放在里面。