decorator pattern: value of field of concrete component is the value of field from component, but why?
我在玩《头一个设计模式》这本书的装饰模式示例。我认为,
有人能解释一下吗?我们是根据接口进行编码的(在本例中,它是一个抽象类),但我仍然在实例化类houseBlend,因此值应该是"house Blend Coffee",但它不是……
下面的代码不包含示例的所有类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class StarbuzzCoffee { public static void main(String[] args) { Beverage beverage = new Espresso(); System.out.println(beverage.getDescription() +" $" + beverage.cost()); Beverage beverage2 = new DarkRoast(); beverage2 = new Mocha(beverage2); beverage2 = new Mocha(beverage2); beverage2 = new Whip(beverage2); System.out.println(beverage2.getDescription() +" $" + beverage2.cost()); Beverage beverage3 = new HouseBlend(); System.out.println("(added by me)return value of getDescription() without condiment:" + beverage3.getDescription()); beverage3 = new Soy(beverage3); beverage3 = new Mocha(beverage3); beverage3 = new Whip(beverage3); System.out.println(beverage3.getDescription() +" $" + beverage3.cost()); System.out.println("(added by me)value of field desciption:" + beverage3.description); } } |
爪哇咖啡
1 2 3 4 5 6 7 8 9 10 |
调味品decorator.java
1 2 3 4 | public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); } |
家庭语言
1 2 3 4 5 6 7 8 9 10 11 | public class HouseBlend extends Beverage{ public HouseBlend() { description ="House Blend Coffee"; } @Override public double cost() { return .89; } } |
调味品decorator.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Mocha extends CondimentDecorator{ Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() +", Mocha"; } @Override public double cost() { return beverage.cost() + .20; } } |
问题是,你要创造的摩卡酒本身就是一种有描述的饮料。你没有改变它的描述。您正在传递另一种饮料并增强对装饰对象的描述。但是,你仍然有你以前对摩卡物品的描述。当您直接访问它的描述时(这是您不使用get description方法所做的),您将访问未更改的字段,从而打印"未知饮料"。
您创建的每个饮料都将有其字段描述。如果你不换就用,你会得到"未知饮料"。
将类beverage的字符串描述设为protected,并且只能通过实现beverage的重写getdescription方法访问它。过来看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | public class StarbuzzCoffee { public static void main(String[] args) { Beverage beverage3 = new HouseBlend(); System.out .println("(added by me)return value of getDescription() without condiment:" + beverage3.getDescription()); beverage3 = new Mocha(beverage3); System.out.println(beverage3.getDescription() +" $" + beverage3.cost()); System.out.println("(added by me)value of field desciption:" + beverage3.getDescription()); } } abstract class Beverage { protected String description ="Unknown Beverage"; public String getDescription() { return description; } public abstract double cost(); } abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); } class HouseBlend extends Beverage{ public HouseBlend() { description ="House Blend Coffee"; } @Override public double cost() { return .89; } } class Mocha extends CondimentDecorator{ Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() +", Mocha"; } @Override public double cost() { return beverage.cost() + .20; } } |
在设计方面,将Beverage的getDescription抽象化并强制每个实现覆盖它会更安全。这样以后你就可以避免这种问题了。过来看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | public class StarbuzzCoffee { public static void main(String[] args) { Beverage beverage3 = new HouseBlend(); System.out .println("(added by me)return value of getDescription() without condiment:" + beverage3.getDescription()); beverage3 = new Mocha(beverage3); System.out.println(beverage3.getDescription() +" $" + beverage3.cost()); System.out.println("(added by me)value of field desciption:" + beverage3.description); } } abstract class Beverage { protected String description ="Unknown Beverage"; public abstract String getDescription(); public abstract double cost(); } abstract class CondimentDecorator extends Beverage { // You don't need this code here. Because Beverage already // provides a getDescription // public abstract String getDescription(); } class HouseBlend extends Beverage{ public HouseBlend() { description ="House Blend Coffee"; } @Override public String getDescription() { return description; } @Override public double cost() { return .89; } } class Mocha extends CondimentDecorator{ // Also make sure that this guy here is private // so other objects can't change or access // its state without going through Mocha private Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() +", Mocha"; } @Override public double cost() { return beverage.cost() + .20; } } |