Pergunta

I'm reading about "Factory method" design pattern from "Head First Design Patterns". So, there is a class

public class PizzaStore {

    SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String type) {

        Pizza pizza;

        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

As you can see above, we store factory and then call createPizza(String) virtual function and this will call appropriate createPizza(...) function for the concrete factory class, e.g., NYStylePizzaFactory or ChicagoStylePizzaFactory. But then author continues:

But you’d like a little more quality control...!

and does the following changes in the code:

public abstract class PizzaStore {

    public Pizza orderPizza(String type) {
        Pizza pizza;

        pizza = createPizza();
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    abstract Pizza createPizza();
}

public class NYStylePizzaStore : PizzaStore {
    Pizza createPizza() {
        return new NYStylePizza();
    }
}

public class ChicagoStylePizzaStore : PizzaStore {
    Pizza createPizza() {
        return new ChicagoStylePizza();
    }
}

So, I don't understand why we gain more quality control in the latter case? It seems that the result is the same - appropriate virtual function is called.

Foi útil?

Solução

I don't have the book but I found some awesome slides about this topic. I will assume that the slides follow the book. They seem to confirm my initial guess that this is about control over pizza creation.

In the first example the store delegates pizza creation to the factory, which is injected from outside by the creating code. The store itself has no say on how pizzas are created, it just asks for them to the factory.

In the second example the store controls pizza creation via createPizza.

Now you ask "[i]sn't it more logical that concrete factory should create a pizza and not the store?"?

Note that in the second example we have a factory too, only it is a method instead of an object. So let me reword the question:

Isn't it more logical to use an injected factory instead of a factory method?

Maybe so. My slides suggest that you as the franchiser want to give the stores control over pizza creation while retaining control over order preparation, which makes sense, and the bit about quality control seems to refer to this.

But from there it jumps to "what you'd really like to do is create a framework that ties the store and the pizza creation together" and I can't see why.

It is true that an abstract base class implementing orderPizza and subclasses implementing createPizza is the more straightforward model of the above and this gives the author a good excuse to introduce the factory pattern. But the map is not the territory and software designers have different concerns than franchisers and franchisees of pizza stores. It is not necessarily true that the more straightforward model is the best one and control in the real world is not the same as control in OO software.

Outras dicas

It's a difference between checking the correctness of something at run time (example #1) or compile time (example #2).

The first example requires you to pass around a string to determine the type of pizza, which can introduce the possibility of runtime errors:

PizzaStore store = new PizzaStore();
Pizza pizza1 = store.orderPizza("chicago style"); // Seems right
Pizza pizza2 = store.orderPizza("blue jeans");    // Blatantly wrong, but compiles

The second pizza type will probably not be understood by the pizza factory (who ever heard of a "blue jeans" pizza?) and at that point the pizza factory will throw an exception.

The second example verifies the correctness of your pizza types at compile time because you are using classes and inheritance for both the pizza stores and pizza styles.

First, let me quote the complete paragraph from P109 of the book:

" But you’d like a little more quality control...!

So you test marketed the SimpleFactory idea, and what you found was that the franchises were using your factory to create pizzas, but starting to employ their own home grown procedures for the rest of the process: they'd bake things a little differently, they'd forget to cut the pizza and they'd use third-party boxes."

Below is my understanding to this paragraph, that is, why did the author claim that the 'quality control" could be any issue if we were to use a Simple Factory pattern in this case.

Imagine the owner of one franchise decides not to pay the franchise fee anymore, and would like to turn it into a knock-off store, i.e., from a pizza hut to a pizza hat.

Previously, he has been doing (because he is located in NYC):

NYStylePizzaStore nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
Pizza pizza = nyStore.order("Veggie") // This is a good veggie pizza to eat!

Now, he decides to do the following:

NYStylePizzaStore nyFactory = new NYPizzaFactory();
Pizza pizza = nyfactory.createPizza("Veggie")
pizza.box() // why are we boxing a raw pizza?
pizza.cut() // and now we're cutting the entire box?
pizza.bake() // and bake it?

Notice that he is not doing things in the right order! And the customer would end up getting a oily box containing a burned pizza. What's worse, the customer thought that they are getting the pizza from a legit pizza hut (He never noticed the store name has been secretly changed to pizza hat!). This would totally ruin the reputation of your franchising business.

I believe the point here is that we should properly encapsulate the factory logic, instead of exposing it to the general public, by using the Factory Method Pattern. That would help improve the "quality control" problem, because no one can easily add his own "improvements" to the PizzaStore procedure anymore (He would not have access to an unbaked, raw pizza at the first place.)

In other words, you should only get to use the pizza factory if you are paying the franchise fee and being a legit franchise owner. The pizza creation procedure and the pizza making procedure should really be tied together.

Licenciado em: CC-BY-SA com atribuição
scroll top