2

我正在阅读 Head First Design Patterns 一书,在第 4 章的“声明工厂方法”部分,该方法被声明为受保护:

public abstract class PizzaStore {

    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare(); // other methods follow

        return pizza;
    }

    protected abstract Pizza createPizza(String type);

}

这让我很困惑,因为我最初认为,实际上这本书中也有说明,拥有一个工厂(方法)可以让你有一个为你创建实例的地方,不仅用于稍后执行操作,还用于“查询”。“采取行动”是指pizza.cut()等,“查询”是指pizza.isSpicy()

关键字不会protected将查询限制为仅子类和相同包类吗?如果第 3 方班级需要在点餐前知道披萨是辣的怎么办?

我可能想多了,因为突出显示框并没有说它必须protected存在,但它在示例代码中。

4

1 回答 1

2

这让我感到困惑,因为我最初认为,实际上这本书中也有说明,拥有一个工厂(方法)可以让你有一个为你创建实例的地方,不仅用于稍后执行操作,还用于“查询"

  • 如果您希望客户端(即调用代码)控制 a 何时Pizza“创建”,那么您不会使该createPizza方法受到保护;这将是一个公共方法,任何引用实例的人PizzaStore都可以调用它。

  • 如果您考虑该类,则其语义orderPizza明显不同createPizza-前者处理调用者请求资源,而后者处理获取该资源,无论是创建新资源还是重新使用旧资源。

  • 所以在这种情况下,很明显,PizzaStore该类希望保留对实际“创建”比萨饼的时间的控制,这就是它受到保护的原因。(也因为继承自的类也PizzaStore可以实现该方法 - 如果它是私有的,则无法看到它以实现它 - 请注意,由于它是抽象的,因此子类必须实现它)。所以创建过程(正如 Ananthu 也提到的)安全地封装在商店中。

让我们假设 a 的实际“创建”Pizza是一个非常昂贵的操作;我们不希望任何人来决定它何时发生。因此,通过保护工厂方法,它允许PizzaStore做出诸如(伪代码,我不懂 Java)之类的决定:

public abstract class PizzaStore {

    protected PizzaBin bin;

    //customer orders a pizza
    public Pizza orderPizza(String type) {
        //maybe we already have one...
        Pizza pizza = HeresOneWeMadeEarlier(type);
        if (pizza !=null) return pizza;
        //nope, we have none, so we have to make one.
        pizza = createPizza(type);
        pizza.prepare(); // other methods follow
        return pizza;
    }
    
    //customer returns a pizza
    public void ReturnPizza(Pizza pie) {
     if(!pie.HasAllSlices()){
       throw new CannotReturnPartiallyEatenPizzaException();
      }
     //hmm. maybe we can re-use this later on...
     bin.store(pie);        
    }
  
    //check if we have a pizza in the bin.
    protected Pizza HeresOneWeMadeEarlier(String type){
        if(bin.contains(type)){
          //we never said this was a *nice* pizza store!
            return bin.takeOutAndDustOff(type);
        }
        else{
          return null;
        }
    }

    protected abstract class Pizza createPizza(String type);

}

也许不是一个买披萨的好地方,但我希望你明白我的意思:)

“执行”是指 Pizza.cut() 等,“查询”是指 Pizza.isSpicy()。

请记住,这些是 a 上的方法Pizza,而不是 a PizzaStore,因此它们在这里并没有真正发挥作用 - 当调用者获得它们的 时Pizza,它们将能够调用 aPizza具有的任何公共方法(eatcutshare等。 ) 并且PizzaStore可能不再对它感兴趣。

希望有帮助。

更新

只是为了解决你也有的一点:

如果第 3 方班级需要在点餐前知道披萨是辣的怎么办?

在这种情况下,您将设计一种方法,PizzaStore该方法将列出成分或选项,以及它们是否辣。

  • 然后,当客户订购披萨时(指定选项列表),他们已经根据他们拥有的选项列表知道它是否辣。
  • 另一个客户,如果他们有订单号,大概可以查看订单的详细信息,其中包括在请求比萨时选择的选项,因此也可以确定比萨是否辣。
于 2015-08-30T23:25:26.480 回答