Decorator方法,Java中的一个Decorator类型

时间:2014-03-05 23:02:33

标签: java design-patterns decorator

我正在学习使用装饰器模式,我遇到了一个问题,我认为这很简单,但我似乎无法找到答案。 假设我有一个抽象的Beverage类。然后让我说我有几个具体组件扩展Beverage:americano,espresso,latte等。还有一个抽象的Condiment类扩展Beverage。然后调味品类有多个子类:牛奶,糖,大豆,鞭子。每个调味品子类都有一个成本和getdescription()方法,分别从Beverage和Condiments继承。我的问题是,如何在测试时停止某个饮料实例中含有多种与之相关的相同类型的调味品,即美洲大豆只收到大豆一次,即使大豆在测试类中被说了两次。我知道我可以将调味品保存到列表中,并在添加新调味品时检查它是否存在,我只是想看看是否存在更好的选择。

饮料类

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 Class

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

}

如果有人可以帮助甚至指出我的好文章或教程,我将非常感激。

1 个答案:

答案 0 :(得分: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()中的额外换行,是否失败(抛出异常)。

如果你在包装时停止多次换行,它可能更干净,更不容易出错。那将是构造函数。您可以在抽象类中编写一个通用函数来使用反射来检查它(不会在不支持它的语言中工作),或者解析包装对象的描述以找到它自己的字符串(如果装饰没有那么可靠性较低)有独特的名字。)

我看到的最大问题是调味品包装Beverages,并且通过设计(信息隐藏),调味品不“知道”它们包装其他调味品。您编写的任何代码都可能是脆弱的(可能违反了开放原则)。然而,这是设计上的权衡。你不能拥有一切,所以决定什么更重要(停止多次换行,或者设计允许添加新装饰而不破坏任何东西)。

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

但更好的方法可能是{,1}在“,”字符上并检查这些字符串,因为描述只是使用逗号连接(在.split()中)。

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