Reputation: 675
I'm reading the Head First Design Patterns book and on the "Declaring a factory method" section in Chapter 4, the method is declared as protected:
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);
}
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".
By "acting on" I mean pizza.cut()
etc, and by "querying" I mean pizza.isSpicy()
.
Wouldn't the protected
keyword limit the querying to only the subclasses and same-package classes? What if a 3rd-party class needed to know that the pizza is spicy before ordering?
I may be overthinking this, because the highlight box does not say it HAS to be protected
but it's there in the sample code.
Upvotes: 2
Views: 608
Reputation: 7485
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"
If you wanted the client (that is, the calling code) to be in control of when a Pizza
gets "created" then you wouldn't make the createPizza
method protected; it would be a public method and anyone with a reference to an instance of PizzaStore
could call it.
If you think about that class, the semantics of orderPizza
are clearly different from createPizza
- the former deals with a caller asking for a resource, whereas the latter deals with obtaining that resource, whether this be creating a new one or re-using an old one.
So in this case, it's clear that the PizzaStore
class wants to retain control over when a pizza actually gets "created", and this is why it's protected. (also because a class that inherits from PizzaStore
can also implement the method - if it were private it couldn't see it in order to implement it - and note that since it's abstract, a subclass has to implement it). So the creation process is (as Ananthu also mentioned) safely encapsulated within the store.
Let's suppose that the actual "creation" of a Pizza
is a really expensive operation; we don't want just anyone to decide when it happens. Therefore by keeping the factory method protected, it allows the PizzaStore
to make decisions such as (pseudo-code, I don't know 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);
}
Maybe not a very nice place to get a Pizza, but I hope you see what I mean :)
By "acting on" I mean pizza.cut() etc, and by "querying" I mean pizza.isSpicy().
Bear in mind that these are methods on a Pizza
, not a PizzaStore
, and so therefore they don't really come into play here - when the caller is given their Pizza
, they will be able to call whatever public methods a Pizza
has (eat
, cut
, share
, etc.) and the PizzaStore
probably doesn't have any interest in it any more.
Hope that helps.
Just to address one point you had as well:
What if a 3rd-party class needed to know that the pizza is spicy before ordering?
In that case, you'd design a method on PizzaStore
that would give a list of ingredients or options, and whether or not they were spicy.
Upvotes: 2