【问题标题】:Decorator method, one Decorator type in Java装饰器方法,Java 中的一种装饰器类型
【发布时间】:2014-04-08 07:28:04
【问题描述】:

我正在学习使用装饰器模式,遇到了一个我认为很简单但似乎找不到答案的问题。 假设我有一个抽象的 Beverage 类。然后假设我有一些扩展饮料的具体组件:美式咖啡、浓缩咖啡、拿铁咖啡等。还有一个扩展饮料的抽象调味品类。 Condiments 类有多个子类:牛奶、糖、大豆、鞭子。每个调味品子类都有一个分别从 Beverage 和 Condiments 继承的 cost 和 getdescription() 方法。我的问题是,我如何阻止某个 Beverage 实例在测试时与其关联的同一类型的调味品不止一种,即美式咖啡只收取一次大豆费用,即使大豆在测试课程中被提及两次。我知道我可以将调味品保存到列表中并在添加新调味品时检查它是否存在,我只是想看看是否存在更好的选择。

饮料类

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

}

如果有人可以帮助我,甚至可以为我提供一篇好的文章或教程,我将不胜感激。

【问题讨论】:

  • 您要求为装饰器提供一种idempotence(至少是那些修改 cost() 的)。

标签: java design-patterns decorator


【解决方案1】:

听起来像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() 中的额外换行,是否失败(抛出异常)。

如果您在包装时停止多次包装,它可能会更清洁且不易出错。那将在构造函数中。您可以在抽象类中编写一个通用函数,使用反射检查这一点(在不支持它的语言中不起作用),或者解析包装对象的描述以找到它自己的字符串(如果装饰不那么可靠) t 有唯一的名称)。

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

使用 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 布尔属性来表示“allowsMultiple”并对其进行编码。

【讨论】:

  • 谢谢。很好的答案。我将逻辑重构到 CondimentDecorator 类并且效果很好!
猜你喜欢
  • 1970-01-01
  • 2020-01-11
  • 2014-01-14
  • 2012-02-29
  • 2020-01-02
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 2020-09-03
相关资源
最近更新 更多