我正在尝试学习装饰器设计模式。在这个例子中,我创建了一个应用程序,它根据咖啡的类型(浓缩咖啡、无咖啡因、混合咖啡)、大小(高、大、文蒂)和调味品(大 bean 、生奶油、蒸牛奶)计算咖啡的成本-- 为简洁起见,排除了一些代码。

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

如果我 setSize(GRANDE),然后装饰对象,getSize() 返回 TALL(在 Beverage 类中设置的默认值)。

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

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

问题: 有没有办法对此进行编码,因此当我 setSize() 时,即使在对象被装饰之后,它也会保持该值?

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

如果我在装饰对象后再次 setSize() ,则大小将正确打印为 GRANDE:
        beverage3.setSize(Size.GRANDE);
        System.out.println( beverage3.getSize() + " " + beverage3.getDescription() + " $" + String.format("%.2f", beverage3.cost() ));
    }
}

输出::

高屋混合咖啡 $0.89

GRANDE House 混合咖啡 $0.89

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

GRANDE House 混合咖啡 $0.89

TALL House Blend 咖啡,大 bean 1.04 美元

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

GRANDE House 混合咖啡 $0.89

GRANDE House 混合咖啡,大 bean 1.04 美元

最佳答案

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

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

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

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

关于java - 装饰对象时变量重置为默认值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34047373/

10-10 20:18