Problem understanding Factory Method Pattern

Hi All,

I am trying to understand Factory Method pattern from HF- Design pattern.

However i am unable to understand how Subclassing the PizzaStore is better than creating the invidiual region specific PizzaFactories.

The author gives an example of SimpleFactory and then creates region specific NYPizzaFactory and ChicagoPizzaFactory.

PizzaStore class is initialized with the necessary NYPizzaFactory/ChicagoPizzaFactory object and this code is as good as any thing i can think of. If necessary we can create more region specific pizza factories.

The Factory Method pattern makes us define a abstract parent class for which various subclasses provide implementation of factory method.

Honestly i am very much confused about the advantage of factory method pattern over the other approach.

Please help

[851 byte] By [minkeya] at [2007-11-27 9:20:56]
# 1
Perhaps you could write code that uses this factory approach, and then write the equivalent code that you think is just as good.
jverda at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 2
>>Honestly i am very much confused about the advantage of factory method pattern over the other approach.Explain your question with more details.
Kamal-Mettanandaa at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 3

Initial Scenario : We have a PizzaStore that creates different types of Pizza, Cheese, Veggie etc.

Since we can have many more varieties of pizzas in future, we can move the code for Pizza creation to Simple Factory class

public class PizzaStore {

private SimplePizzaFactory factory;

Public PizzaStore(SimplePizzaFactory factory) {

this.factory = factory;

}

public Pizza orderpizza(String pizzatype) {

Pizza pizza = factory.createpizza(pizzatype);

pizza.prepare();

pizza.bake();

pizza.box();

}

}

public class SimplePizzaFactory {

public Pizza createpizza(String pizzatype) {

Pizza pizza = null;

if(pizzatype.equals("veggie")) {

pizza = new VeggiePizza();

}

else if(pizzatype.equals("cheese")){

pizza = new CheesePizza();

}

return pizza;

}

}

public interface Pizza {

public void prepare();

public void bake();

public void box();

}

public class VeggiePizza implements Pizza {

//dummy code

}

public class CheesePizza implements Pizza {

//dummy code

}

public class Client1 {

public static void main(String[] args) {

SimplePizzaFactory factory = new NYPizzaFactory();

PizzaStore store = new PizzaStore(factory);

Pizza pizza = store.orderpizza("veggie");

}

}

Changed Scenario : We need to open regional branches for this PizzaStore, which will sell localized Pizzas, so we will have few more pizzas specific to the region like NYVegPizza, NYCheesePizza, ChicagoVegPizza, ChicagoCheesePizza and so on for various regions

APPROACH 1:- We can create region specific factory classes that will instantiate region specific pizzas, like NYPizzzaFactory creating NYVegPizza, NYCheesePizzas

We can continue to use the SAME PizzaStore class, just that each regional branch will initalize their respective PizzaStore with the region specific Factory

APPROACH 2: Use Factory Method Pattern

1. Create a Pizza Hierarchy : All Pizzas extend Pizza Interface

2. Define a abstract PizzaStore class with a abstract createpizza method

3. Define region subclasses for PIzzaStore that will create region specific code, basically holding the code similar to what NYPizzaFactory will be holding

public abstract class PizzaStore {

public abstract Pizza createpizza(String pizzatype);

public Pizza orderpizza(String pizzatype) {

Pizza pizza = createpizza(pizzatype);

pizza.prepare();

pizza.bake();

pizza.box();

}

}

public NYPizzaStore extends PizzaStore {

public Pizza createpizza(String pizzatype) {

Pizza pizza = null;

if(pizzatype.equals("veggie")) {

pizza = new NYVegPizza();

}

else if(pizzatype.equals("cheese")){

pizza = new NYCheesePizza();

}

return pizza;

}

}

}

public class Client2 {

public static void main(String[] args) {

PizzaStore store = new NYPizzaStore();

Pizza pizza = store.orderpizza("veggie");

}

}

DOUBTS: - Both Client1 and Client2 is has to choose either NYPizzaStore / ChicagoPizzaStore and thus becomes tightly coupled to the PizzaStore object that we create here.

Which of the 2 approaches is better, creating region specific factories or subclasses of PizzaStore

What are the advantages and disadvantages of each approach?

I hope things will be more clear to you all now.

Looking forward to having a good discussion to appreciate this pattern

minkeya at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 4

Hi Minkey,

Now your question is very clear.

Here's the difference between two approaches.

Approach 1:

Separates the Pizza creation from the user of the pizza object.

Approach 1:

Combine the Pizza creator and the user of the pizza object.

Consider the following scenario. Some clients needs the pizza's ordered using method_1 while some needs method_2.

Order methods

method_1:

pizza.prepare();

pizza.bake();

pizza.box();

method_2:

pizza.prepare();

pizza.bake();

//order procedure changed

pizza.doSomethingElseToo();

//yes, Pizza interface needs to have this new doSomethingElseToo() method

pizza.box();

Now think of how you can achieve this scenario with Approach 2.

One option:

Write two classes like NYPizzaStore and Meth2NYPizzaStore, which would double the number of classes. - not advisable

This order method is not related to any of the countries but depends on what the client requires.

Using Approach 1, you can sub class the PizzaStore easily for method_2.

public class Meth2PizzaStore {

private SimplePizzaFactory factory;

Public PizzaStore(SimplePizzaFactory factory) {

this.factory = factory;

}

public Pizza orderpizza(String pizzatype) {

Pizza pizza = factory.createpizza(pizzatype);

pizza.prepare();

pizza.bake();

pizza.doSomethingElseToo();

pizza.box();

}

}

public class Client3 {

public static void main(String[] args) {

SimplePizzaFactory factory = new NYPizzaFactory();

PizzaStore store = new Meth2PizzaStore(factory);

Pizza pizza = store.orderpizza("veggie");

}

}

So user and creator are decoupled in Approach 1.

HTH.

Kamal-Mettanandaa at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 5

Hi Kamal,

Thanks for your reply.

I have taken this example from Head First- Design patterns book.

Assuming the Pizza interface does not change as suggested by you. The only thing that can change is the type of pizza, i.e. new varities of pizza can get added like ChickenPizza, etc.

The question here is which approach is better for instantiating objects, Approach 1 or Approach 2.

Author seems to suggest that Approach 2 is better as it creates a framework sort of a thing.

Please advice

regards

minkeya at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 6

Hi Minkey,

(Yes, this was from HFDP Factory chapter). There's no way that we can guarantee this Pizza interface is not going to change in future. So when I design is done, we should assume that these can happen and apply what would help you most in maintaining the code. So as I explained in the previous post, approach 2 is better in terms of decoupling. Why shouldn't we choose the better one?

Even if you think there's no change in the Pizza interface, what if a need arises for changing the way the pizza is ordered.

So I suggest, it's better to think in terms of maintainability of the system.

Kamal

My blog: http://lkamal.blogspot.com

Kamal-Mettanandaa at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 7

Hi Kamal,

I am still not able to understand this.

As per my understanding, the example you have provided seems to suggest Approach 1 (used with SimpleFactory) is better

Moreover as the book HF-Design Patterns suggest, the trade-off is for the better approach for creating objects.

Although you point is really valid from the point of view of future changes in order() method.

Many thanks for your help

minkeya at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 8

Hi Minkey,

Ok, so you want to think in terms of 'no changes to order operations and only the change would be to create method'.

If that is guaranteed, then there's no need for separating the creator and user. Then you can choose one from the two approaches that they have provided in the book.

But still there's a saying, "favor composition over inheritance". So still Approach 2 wins over 1.

Whole point in Factory Method is to separate the object creation from the user (class or method) so that the changes in the creation would not affect the user. So that's why a SimpleFactory method or a sub class should instantiate.

Why should we integrate and couple features that could be easily separated?

Regards,

Kamal

Blog: http://lkamal.blogspot.com

Kamal-Mettanandaa at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 9

Hi Kamal,

Thanks a lot for your patience, help and sparing your precious time.

I think we are getting close to an agreement.

However, as i understand from your 2nd reply,

Approach 1: Create SimpleFactory or region specific factories like NYPizzaFactory, ChicagoPizzaFactory

There will be a single PIzzaStore class. Which will hold reference to the SimpleFactory object.

Approach 1 involves Composition.

Approach 2: Also called Factory Method Pattern. Define a abstract PizzaStore with a abstract create method and implementation of create method will be given by subclasses of the PizzaStore like NYPizzaStore, ChicagoPizzaStore.

Approach 2 involves Inheritance

So as you pointed out "favor composition over inheritance".

That way Approach 1 should be better than Approach 2.

Approach 1 ensures that object creation is encapsulated in a different class.

Moreover, please can you clarify on the point, "

Whole point in Factory Method is to separate the object creation from the user (class or method) so that the changes in the creation would not affect the user. "

In case i move object instantiation to a separate class like SimpleFactory class, i can simply add new object (Pizzas like ChickenPizza etc.) to create() of SimplePizzaFactory.

It should not effect the client?

Please clarify

thanks & regards

minkeya at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 10

Hi Minkey,

Extremely sorry, I had made a mistake in last 2 posts by mixing the two words, Apprach 1 and Approach 2.

Let me tell it again.

Approach 1:

This decouples creator from user - composition

Approach 2:

Couples creator and user - inheritance

I was trying to tell that approach 1 is better than 2. (This time correctly said).

The scenario I said previously was also favored approach 1.

If 'no changes to order operations and only the change would be to create method'. - the both match the requirement. But still I would favor approach 1 due to composition.

Your examples:

eg 1. Uses a simple factory to create Pizza but the subclasses of the simple factory decides what to instantiate. So this is also a similar to Factory pattern, but does not have a factory method.

eg 2. Uses a Factory method (PizzaStore) and subclasses decide what to instantiate.

Factory method pattern - delegate the instantiation to sub classes, but knows what to do with the created object

Simple factory - decide and instantiate, has no idea what to do with the created object.

So the 2nd example (Factory method), can be considered as a framework for ordering Pizzas while the first is also used for the same purpose, but in a different manner.

BR,

Kamal

Kamal-Mettanandaa at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 11
Hi Kamal,Thanks for the clarification. Awarding you the points now.regards
minkeya at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...
# 12
Always welcome. Thanks.
Kamal-Mettanandaa at 2007-7-12 22:14:27 > top of Java-index,Other Topics,Patterns & OO Design...