当我装饰物体时,变量重置为默认值

我正在努力学习Decorator设计模式。 在这个例子中,我创建了一个应用程序,根据咖啡的类型(意式浓缩咖啡,咖啡豆,混合咖啡),大小(高,大,通风)和调味品装饰(大豆,奶油,蒸牛奶) - 为简洁起见,排除一些代码。

从底部的输出中可以看到,如果setSize(GRANDE)并不包装对象,getSize()将返回GRANDE。

如果我设置了大小(GRANDE),然后修饰该对象,则getSize()返回TALL(在Beverage类中设置的默认值)。

如果我setSize(GRANDE),装饰对象,setSize(GRANDE),然后getSize()返回GRANDE。

注意:虽然尺寸打印不正确,但成本计算正确。

问题:有没有一种方法可以对它进行编码,所以当我设置了Size()时,即使在装饰对象后它仍然保持该值。

package coffee;

public abstract class Beverage {
    String description = "Unknown Beverage";
    public enum Size { TALL, GRANDE, VENTI };
    Size size = Size.TALL;

    public String getDescription() {
        return description;
    }

    public void setSize(Size size) {
        this.size = size;
    }

    public Size getSize() {
        return size;
    }

    public abstract double cost();
}

package coffee;

public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

package coffee;

public class HouseBlend extends Beverage {

    public HouseBlend() {
        description = "House Blend Coffee";
    }

    public double cost(){
        return .89;
    }
}

package coffee;

public class Soy extends CondimentDecorator {
    Beverage beverage;

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

    public String getDescription() {
        return beverage.getDescription() + ", Soy";
    }

    public double cost() {
        double cost = beverage.cost();
        if( beverage.getSize() == Size.TALL) {
            cost += .10;
        } else if( beverage.getSize() == Size.GRANDE) {
            cost += .15;
        }else if( beverage.getSize() == Size.VENTI) {
            cost += .20;
        } 
        return cost;
    }   
}

package coffee;
import coffee.Beverage.Size;
public class StarbuzzCoffeeController {

    public static void main(String[] args) {
        Beverage beverage = new HouseBlend();
        System.out.println( beverage.getSize() + " " + beverage.getDescription() + " $" + String.format("%.2f", beverage.cost() ));
        beverage.setSize(Size.GRANDE);
        System.out.println( beverage.getSize() + " " + beverage.getDescription() + " $" + String.format("%.2f", beverage.cost() ));
        System.out.println("-----------------------");

        Beverage beverage2 = new HouseBlend();
        beverage2.setSize(Size.GRANDE);
        System.out.println( beverage2.getSize() + " " + beverage2.getDescription() + " $" + String.format("%.2f", beverage2.cost() ));

如果我不跟着另一个setSize(),它会在下一行打印“TALL”作为大小:

        beverage2 = new Soy(beverage2); 
        System.out.println( beverage2.getSize() + " " + beverage2.getDescription() + " $" + String.format("%.2f", beverage2.cost() ));
        System.out.println("-----------------------");

        Beverage beverage3 = new HouseBlend();
        beverage3.setSize(Size.GRANDE);
        System.out.println( beverage3.getSize() + " " + beverage3.getDescription() + " $" + String.format("%.2f", beverage3.cost() ));
        beverage3 = new Soy(beverage3);

如果在装饰完对象后再次设置了Size(),则大小将正确打印为GRANDE:

        beverage3.setSize(Size.GRANDE);
        System.out.println( beverage3.getSize() + " " + beverage3.getDescription() + " $" + String.format("%.2f", beverage3.cost() ));
    }
}

输出::

TALL House混合咖啡$ 0.89

GRANDE House混合咖啡$ 0.89

-----------------------

GRANDE House混合咖啡$ 0.89

TALL House混合咖啡,大豆$ 1.04

-----------------------

GRANDE House混合咖啡$ 0.89

GRANDE House混合咖啡,大豆$ 1.04


您的类Soy不会覆盖getSize()方法 - 因此,将使用基类的默认实现。 基类返回自己的size成员,它被初始化为TALL。

为了解决这个问题,你必须在你的类Soy相应地重写getSize()方法:

@Override
public Size getSize() {
    return this.beverage.getSize();
}

这将正确返回装饰对象的大小。


你的装饰模式的实现在概念上是不正确的。 您遇到的问题来自不正确的实施。

我在下面提到这篇维基百科文章中的5个条目:https://en.wikipedia.org/wiki/Decorator_pattern

  • “将原”Component“类继承为”Decorator“类;”
  • 在你的情况下,“组件”是BeverageCondimentDecorator是装饰者
  • “在Decorator类中,将Component指针添加为一个字段;”
  • 将Component指针添加为一个字段。 您添加了Soy领域的Beverage beverage ,而不是将其添加到CondimentDecorator
  • “将一个Component传递给Decorator构造函数以初始化Component指针;”
  • 这也应该在CondimentDecorator完成
  • “在Decorator类中,将所有”Component“方法重定向到”Component“指针”
  • 你没有这样做,这是你问题的根源。 在CondimentDecorator ,默认情况下, getSize()应该调用beverage.getSize() 。 其他领域也应该如此。
  • 我认为你应该回到装饰者模式试图实现的基础知识上,并且用正确的想法来重建你的实现。 您可能能够以更简单的方式解决您的问题,但是您可能对装饰模式的实际内容有错误的想法。

    请牢记以下主要观点:

  • 饮料是你的组件,
  • CondimentDecorator是你的装饰者,
  • 大豆是一个ConcreteDecorator

  • 如果您想要“原始”饮料的价值,我认为您必须将getSize()委托给包装/装饰实例。

      Beverage cappuccino = new Cappuccino(Size.VENTI);
      Beverage soyMilkCappuccino = new Soy(cappuccino);
    

    Soy

      class Soy extends Beverage {
           private final Beverage decorated;
           Soy(Beverage other) { this.decorated = other; }
           // delegation
           Size getSize() { return decorated.getSize(); }
      }
    
    链接地址: http://www.djcxy.com/p/32007.html

    上一篇: Variable resets to default value when I decorate object

    下一篇: Decorator method, one Decorator type in Java