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

时间:2015-08-29 00:48:37

标签: java design-patterns keyword factory-method

我正在阅读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关键字不会将查询限制为仅限于子类和同包类吗?如果第三方课程在订购前需要知道比萨饼是辣的,该怎么办?

我可能会过度思考这个问题,因为高亮框并没有说明它是protected,但它在示例代码中就已存在。

1 个答案:

答案 0 :(得分:2)

  

这让我感到困惑,因为我最初认为,书中也说过,拥有一个工厂(方法)可以让你有一个地方为你创造一个实例,而不仅仅是为了以后的行动,而且for"查询"

  • 如果您希望客户端(即调用代码)能够控制Pizza何时获得"创建"那么你就不会保护createPizza方法;它将是一种公共方法,任何引用PizzaStore实例的人都可以调用它。

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

  • 所以在这种情况下,很清楚PizzaStore课程想要保持对披萨实际获得"创建"的时间的控制,这就是为什么它" 39;受保护。 (也因为继承自PizzaStore的类也可以实现该方法 - 如果它是私有的,它就不能看到它以实现它 - 并注意,因为它是抽象的,一个子类来实现它)。因此,创建过程(如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);

}

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

  

采取行动"我的意思是pizza.cut()等,并通过"查询"我的意思是pizza.isSpicy()。

请记住,这些是Pizza上的方法,而不是PizzaStore,所以他们并没有真正发挥作用 - 当来电者被给予他们{{1 }},他们可以调用Pizza所拥有的任何公开方法(Pizzaeatcut等等,而share可能不会再也没兴趣了。

希望有所帮助。

更新

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

  

如果第三方课程在订购前需要知道比萨饼是辣的,该怎么办?

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

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