java - 装饰器模式 : value of field of concrete component is the value of field from component, 但为什么呢?

标签 java decorator

我正在研究《Head First Design Patterns》一书中的装饰器模式示例。我以为beverage3字段描述的值必须是“House Blend Coffee”,但实际上是“Unknown Beverage”。

有人能解释一下吗?我们正在针对接口(interface)进行编码(嗯,在本例中它是一个抽象类),但我仍在实例化 HouseBlend 类,因此该值应该是“House Blend Coffee”,但它不是...

下面的代码不包含示例的所有类。

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

饮料.java

public abstract class Beverage {

    String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

CondimentDecorator.java

public abstract class CondimentDecorator extends Beverage {

    public abstract String getDescription();
}

HouseBlend.java

public class HouseBlend extends Beverage{

    public HouseBlend() {
        description = "House Blend Coffee";
    }
    @Override
    public double cost() {
        return .89;
    }

}

CondimentDecorator.java

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

}

最佳答案

问题是您正在创建的 Mocha 对象本身就是一个具有描述的饮料。您没有更改其描述。您正在传递另一种饮料并增强对装饰对象的描述。但是,您仍然保留了以前对 Mocha 对象的描述。当您直接访问其描述时(这就是您不使用 getDescription 方法所做的事情),您将访问未更改的字段,因此您将打印“未知饮料”。

您创建的每种饮料都会有其字段描述。如果你不改变它而使用它,你会得到“未知饮料”。

保护类 Beverage 的字符串描述,并且只能通过 Beverage 实现的重写 getDescription 方法来访问它。检查一下:

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 抽象化并强制每个实现都覆盖它会更安全。这样您将来就可以避免此类问题。检查一下:

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

}

关于java - 装饰器模式 : value of field of concrete component is the value of field from component, 但为什么呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47607545/

相关文章:

c++ - 装饰者模式中的装饰顺序

java - 如何在 Java 中声明 "Member Fields"?

java - 将值与 ArrayList Java 的特定对象进行比较时出现问题

java - 如何访问子类中抽象类的重写的非静态方法

java - 关键字 "this"和 "toString"到底是什么意思和作用?

python - 如何将带有装饰器的方法添加到 python 中的类?

java - 从另一个带有元素的 svg 图像创建一个带有嵌入 base64 字符串的 SVG 图像

python - 如何在无法访问其定义的函数上使用 python 装饰器?

python - 方法执行后提交 - 装饰器

python - 如何在Python中向继承方法添加装饰器而不复制整个方法?