【问题标题】:How to make sure a specific decorator class isn't already decorating my object?如何确保特定的装饰器类尚未装饰我的对象?
【发布时间】:2015-04-17 19:22:14
【问题描述】:

我有一个装饰器类,它基本上围绕着一个名为 Drink(咖啡饮料)的类。你可以用一杯浓缩咖啡、巧克力、焦糖来装饰你的饮料。我知道如何实现这一点,并且我做了一个非常基本的装饰器实现。

如何更改我的鲜奶油类以确保它只能添加到饮料中一次?

public class WCream extends DrinkDecorator
{
   private final String TYPE = "Whipped Cream";
   private final double COST = 1.00;
   private Drink drink;


   public WCream(Drink d)
   {
      this.drink = d;  
   }

   public String getType()
   {
      return drink.getType() + ", " + TYPE;
   }

   public double cost()
   {
      return COST + drink.cost();
   }


}

这是我尝试实现 Singleton 以使其工作的方式,这可以避免重复的生奶油,但它会跳过我添加的下一个东西......所以如果我在生奶油之后添加巧克力,它不会'不加巧克力。

然后,在我使用的测试器类中

myDrink = WCream.getUniqueInstance(myDrink); 
//instead of
myDrink = new WCream(myDrink);

这是我为其他装饰器所做的方式。

public class WCream extends DrinkDecorator
{
   private final String TYPE = "Whipped Cream";
   private final double COST = 1.00;
   private Drink drink;

   private static Wcream uniqueInstance;


   public WCream(Drink d)
   {
      this.drink = d;  
   }

   public static WCream getUniqueInstance(Drink d)
   {
      if(uniqueInstance == null)
          uniqueInstance = new WCream(d)

      return uniqueInstance;
   }   

   public String getType()
   {
      return drink.getType() + ", " + TYPE;
   }

   public double cost()
   {
      return COST + drink.cost();
   }


}

【问题讨论】:

  • 1.我打赌 DrinkDecorator 实现或扩展了 Drink,对吧? 2. 我不会称之为“单例”,而是装饰器上的一个条件。
  • 使用DrinkBuilder 为您处理这些情况。
  • 是的。有人建议我“修改单例”以使其工作,但这也有效。我不想在测试仪中通过询问我是否已经添加了生奶油来修复它。我想让饮料知道我有没有。
  • @DavidGrinberg 这是因为它可以动态添加。这就是Decorator Pattern 的目的。
  • 编辑了我原来的问题以包含更多信息。

标签: java decorator


【解决方案1】:

糟糕的答案:

使用字符串比较在构造函数中验证它

  public WCream(Drink d) {
    if (d.getType().containsAll("WHIPPED CREAM") { 
       KABOOOM
    }
    this.drink = d;
  }

稍微好点:

提供一些方法来返回装饰器或层或其他东西的列表:

 public List<Components> getComponents() {
    List<Components> list = new ArrayList<>();
    list.add(Component.WHIPPED_CREAM);
    list.addAll(this.drink.getComponents());
    return list;
 }

然后在构造函数中执行相同的验证,但现在只使用常规集合包含

   public WCream(Drink d) {
    if (d.getComponents().contains(Component.WHIPPED CREAM)) { 
       KABOOOM
    }
    this.drink = d;
  }

更好的答案,但这很大程度上取决于你想做什么:

提供某种构建器,您可以根据需要配置它,并且在某些时候将您的 Drink 与所有需要的装饰器组装起来,它将集中创建对象协作的一些困难并执行所需的验证

【讨论】:

  • 为此目的,一个集合比一个列表要好得多。查找更有效,并且保证了唯一性。如果您想保留顺序,请使用 LinkedHashSet。
  • 嗯,是的,也不是。是的,如果他确保应该只添加每个组件中的一个。如果我的拿铁咖啡可以加双 CINNAMON_SHOT,则为假。
  • 是的。虽然我会通过装饰镜头(装饰装饰器)来解决这个问题。
  • 顺便说一句,除了查找之外,以这种方式创建集合根本没有效率(如果我们认为我使用的是 ArrayList 则更多)。我正在寻找是否可以在 java 中使用一些东西来构建一个像 head :: tail 这样的集合(就像我在函数式语言中所做的那样),但我没有找到任何东西(看起来也不多)
  • 不幸的是,我知道的任何库中都没有功能列表实现。也许functionjava有一个,我不知道。实际上在 javac 的源代码中有一个,但是导入编译器只是为了获得它使用的数据结构感觉很奇怪
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-15
  • 1970-01-01
  • 2018-01-12
  • 2021-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多