为什么工厂方法被声明为受保护的?

Why is the factory method declared as protected?

我正在阅读 Head First Design Patterns 一书,在第 4 章的 "Declaring a factory method" 部分,该方法被声明为受保护的:

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

}

这让我很困惑,因为我最初认为,事实上书中也有说明,拥有一个工厂(方法)可以让你有一个地方为你创建一个实例,而不仅仅是为了以后的行动还有 "querying"。 "acting on" 我的意思是 pizza.cut() 等, "querying" 我的意思是 pizza.isSpicy().

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

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

This confuses me because I initially thought, in fact it is also stated in the book, that having a factory (method) allows you to have a single place that creates an instance for you, not just for acting on later but also for "querying"

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

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

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

让我们假设 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);

}

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

By "acting on" I mean pizza.cut() etc, and by "querying" I mean pizza.isSpicy().

请记住,这些是 Pizza 上的方法,而不是 PizzaStore 上的方法,因此它们在这里并没有真正发挥作用 - 当调用者被赋予 Pizza,他们将能够调用 Pizza 具有的任何 public 方法(eatcutshare 等)和 PizzaStore 可能对它不再有任何兴趣了。

希望对您有所帮助。

更新

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

What if a 3rd-party class needed to know that the pizza is spicy before ordering?

在那种情况下,您将在 PizzaStore 上设计一个方法,该方法将提供成分或选项列表,以及它们是否辛辣。

  • 然后当客户点披萨(指定选项列表)时,他们已经根据他们的选项列表知道它是否辣。
  • 另一个客户,如果他们有订单号,大概能够查找订单的详细信息,其中包括在请求比萨饼时选择的选项,因此也可以确定比萨饼是否是辣不辣