将常见成员变量放在装饰器中的位置

时间:2016-03-30 11:12:14

标签: oop decorator

鉴于经典的咖啡装饰示例(从维基百科复制而来)。

public interface Coffee {
    public double getCost();
}

public class SimpleCoffee implements Coffee {
    public double getCost() {
        return 1;
    }
}

public abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decoratedCoffee;
    public CoffeeDecorator(Coffee c) {
        this.decoratedCoffee = c;
    }
    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

class WithMilk extends CoffeeDecorator {
    public WithMilk(Coffee c) {
        super(c);
    }
    public double getCost() {
        return super.getCost() + 0.5;
    }
}

现在假设所有装饰者(例如牛奶)的价格取决于所有咖啡将具有的某些属性(比如咖啡的大小)以及咖啡的大小从未在其他地方使用过。应该将咖啡大小添加到类层次结构中?

我可以把它放在咖啡界面

public interface Coffee {
    public double getCost(); // Returns the cost of the coffee
    public/protected double size;
}

如果设置为公开,则不必要地暴露大小

如果设置为protected,装饰者无法通过decoratedCoffee真正访问它(请参阅此帖子Java: cannot access a protected member of the superclass in the extending subclassWhy can't a derived class call protected member function in this code?

我可以把它放在CoffeeDecorator中,但是我必须将构造函数修改为

public CoffeeDecorator(Coffee c) {
    if c is of type CoffeeDecorator
        size = c.size;
    this.decoratedCoffee = c;
}

哪种方式看起来不是最优雅的解决方案......(显然在我找到一个非空的大小之前挖掘decoratedCoffee的链也不是一种选择。

我可以把它放在每个装饰器中,这违反了设计原则。

我很确定这种情况经常出现,我想知道处理此类案件的最佳方法是什么?

提前致谢。

---编辑31/3/2016 ---

澄清某些属性(以前的杯子尺寸,现在改名为咖啡尺寸)是所有咖啡都应该有的。

1 个答案:

答案 0 :(得分:0)

我不认为将杯子大小添加到这些课程中是一个好主意。 它只是不适合那里,因为咖啡对杯子一无所知。

Cup可以是一个单独的类(作为伪代码的代码,我对java语法不是很熟悉):

public class Cup {
    private Coffee coffee;

    public Cup(Coffee c) {
        this.coffee = c;
    }

    public getCost() {
        return this.getSize() * c.getCost();
    }

    public getSize() {
        return 1; // standard cup
    }
}

public class BigCup extends Cup {

    public getSize() {
        return 2; // double size
    }

}

现在你可以做new BigCup(new WithMilk(new Coffee()))。 或者Cup也可以是一个装饰者,它在编程方面是有意义的,但在现实生活方面可能没什么意义(因为现在杯子也实现了咖啡,听起来很有趣):

public class Cup extends CoffeeDecorator {

    public Cup(Coffee c) {
        super(c);
    }

    public getCost() {
        return this.getSize() * super.getCost();
    }

    public getSize() {
        return 1; // standard cup
    }
}

public class BigCup extends Cup {

    public getSize() {
        return 2; // double size
    }

}