2014-03-05 125 views
3

我在学习使用Decorator模式的过程中,我遇到了,我估计是简单的一个问题,但我似乎无法找到答案的一个装饰类型。 假设我有一个抽象的饮料类。然后,假设我有几个延伸饮料的具体组件:americano,espresso,latte等。还有一个抽象的调味品类扩展了饮料。调味品类然后有多个小类:牛奶,糖,大豆,鞭子。每个调味品子类都有一个分别从Beverage和Condiments继承的cost和getdescription()方法。我的问题是,在测试时,如何阻止某个具有多种同类型调味品的饮料实例,即美国大豆只有一次收取大豆的费用,即使大豆在测试课程中被陈述了两次。我知道我可以将调味品保存到列表中,并在添加新调味品时检查是否存在调味品,我只想看看是否有更好的选择。装饰方法,在Java

饮料类

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(); 

} 

在DarkRoast类

public class DarkRoast extends Beverage { 

    public DarkRoast() { 
     description = "Dark Roast Coffee"; 
    } 

    public double cost() { 
     return .99; 
    } 

} 

大豆类

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(); 
    } 

} 

如果有人能够帮助,甚至指向我一篇好文章或教程,我将不胜感激。

+0

你正在为修饰器(至少修改cost())的一种[idempotence](https://en.wikipedia.org/wiki/Idempotence)。 – Fuhrmanator

回答

2

听起来像是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()中的额外换行。

,如果你停在总结时多条包装这也可能是更清洁和更小的错误倾向。这将在构造函数中。你可以在抽象类中编写一个通用函数,它使用反射来检查它(不支持不支持它的语言),或者解析被包装对象的描述以找到它自己的字符串(如果装饰不够可靠,没有独特的名字)。

我这样做是调味品包装饮料,并通过设计(信息隐藏)看到的最大的问题,调味品不“知道”他们包装等佐料。你写的任何代码都可能是脆弱的(它可能违反了开闭原则)。然而,这是设计中的折衷。你不能拥有所有东西,所以决定什么更重要(停止多个包装,或者有一个允许添加新装饰器而不破坏任何东西的设计)。

UML Diagram of the key classes

使用getDescription(解析它)将最有意义,很可能,前提是你可以依靠的格式,以确定嵌套。

大豆类可以这样做:

private String myDescription = "Soy" 
public Soy(Beverage beverage) { 
    if (beverage.getDescription().contains(myDescription)) { 
     throw new Exception(); 
} 
    this.beverage = beverage; 
} 

但更好的方法可能是.split()上“”性格和检查这些字符串,因为描述只是使用逗号(在getDescription())级联。

正如我所说,如果禁止所有多个调味品包装的通用规则,您可以将此逻辑重构为CondimentDecorator类,以避免重复代码。你甚至可以使用Decorator布尔属性来表示“allowsMultiple”并为其编码。

+0

谢谢。很好的答案。我重新考虑了CondimentDecorator课程的逻辑,并且非常棒! – NUIG2014