我在学习使用装饰器模式的过程中,遇到了一个我认为很简单但似乎找不到答案的问题。 假设我有一个抽象的 Beverage 类。然后假设我有一些扩展 Beverage 的具体组件:美式咖啡、浓缩咖啡、拿铁等。还有一个扩展 Beverage 的抽象 Condiment 类。 Condiments 类有多个子类:milk、sugar、soy、wip。每个调味品子类都有一个分别从 Beverage 和 Condiments 继承的 cost 和 getdescription() 方法。我的问题是,如何在测试时阻止某个 Beverage 实例具有与其关联的不止一种相同类型的调味品,即即使在测试类中两次提到大 bean ,美式咖啡只收取一次大 bean 费用。我知道我可以将调味品保存到列表中并在添加新调味品时检查它是否存在,我只是想看看是否存在更好的选择。
饮料类
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 DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}
public double cost() {
return .99;
}
}
大 bean 类
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
return .15 + beverage.cost();
}
}
如果有人能帮助我,甚至指出一篇好文章或教程,我将不胜感激。
最佳答案
听起来像 Head First Design Patterns (HFDP) 中的示例?测试用例简单易懂,但做起来可能没那么多。
将装饰器视为包装器。当装饰器要包装某些东西时,它可以检查那个“东西”以查看它是否已经包含它自己类型的装饰器。下面是我稍微改动过的 HFDP 代码:
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Soy(beverage2); // wrap once
beverage2 = new Soy(beverage2); // wrap again (**error case)
您必须决定是否要禁止对所有装饰器进行多次包装,或者某些装饰器可能具有一种“仅一次”属性。另一件要决定的事情是如果发生第二次换行(上面注释中的 ** )或者您是否只想忽略 cost()
中的额外换行是否失败(抛出异常)。
如果您在 wrap-time 停止多次包装,它可能会更干净并且更不容易出错。那将在构造函数中。您可以在抽象类中编写一个通用函数,使用反射检查它(在不支持它的语言中不起作用),或者解析包装对象的描述以找到它自己的字符串(如果装饰不可靠,则不太可靠)没有唯一的名称)。
我看到这样做的最大问题是调味品包装饮料,并且根据设计(信息隐藏),调味品不会“知道”它们正在包装其他调味品。您编写的任何代码都可能是脆弱的(它可能违反开闭原则)。然而,这就是设计中的权衡。您不可能拥有一切,因此请决定什么更重要(停止多重包装,或采用允许添加新装饰器而不破坏任何东西的设计)。
使用 getDescription(解析它)可能最有意义,前提是您可以依赖该格式来识别嵌套。
Soy 类可以这样做:
private String myDescription = "Soy"
public Soy(Beverage beverage) {
if (beverage.getDescription().contains(myDescription)) {
throw new Exception();
}
this.beverage = beverage;
}
但更好的方法可能是 .split()
在 ","字符上并检查这些字符串,因为描述只是使用逗号连接(在 getDescription()
).
正如我所说,如果禁止所有多个调味品包装是一般规则,您可以将此逻辑重构到 CondimentDecorator 类以避免重复代码。您甚至可以使用 Decorator boolean 属性来表示“allowsMultiple”并对其进行编码。
关于java - Decorator方法,Java中的一种Decorator类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22211309/