关于java:decorator模式:具体组件的字段值是组件中字段的值,但为什么呢?

decorator pattern: value of field of concrete component is the value of field from component, but why?

我在玩《头一个设计模式》这本书的装饰模式示例。我认为,beverage3的实地描述的价值必须是"家庭式混合咖啡",但它是"未知饮料"。

有人能解释一下吗?我们是根据接口进行编码的(在本例中,它是一个抽象类),但我仍然在实例化类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
public abstract class Beverage {

    String description ="Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

调味品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;
  }

}