I know similar questions were asked before. I've been reading a lot about this during the last couple of days and I think I can now understand the differences in terms of design and code flow. What bothers me it's that it seems like both pattern can solve the very same set of problems without a real reason to choose one or another. While I was trying to figure this out by myself, I tried to implement a little example (starting from the one I found on "Head First: Design patterns" book). In this example I tried to solve the same problem twice: one time using only the "Factory method pattern" and the other using the "Abstract Factory pattern". I'll show you the code and then I'll make some comments and the question.
Common interfaces and classes
public interface IDough { }
public interface ISauce { }
public class NYDough : IDough { }
public class NYSauce : ISauce { }
public class KNDough : IDough { }
public class KNSauce : ISauce { }
Pure Factory method pattern
// pure Factory method pattern
public abstract class Pizza
{
protected IDough Dough { get; set; }
protected ISauce Sauce { get; set; }
protected abstract IDough CreateDough();
protected abstract ISauce CreateSauce();
public void Prepare()
{
Dough = CreateDough();
Sauce = CreateSauce();
// do stuff with Dough and Sauce
}
public void Bake() { }
public void Cut() { }
public void Box() { }
}
public class NYCheesePizza : Pizza
{
protected override IDough CreateDough()
{
return new NYDough();
}
protected override ISauce CreateSauce()
{
return new NYSauce();
}
}
public class KNCheesePizza : Pizza
{
protected override IDough CreateDough()
{
return new KNDough();
}
protected override ISauce CreateSauce()
{
return new KNSauce();
}
}
public abstract class PizzaStore
{
public void OrderPizza(string type)
{
Pizza pizza = CreatePizza(type);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
}
public abstract Pizza CreatePizza(string type);
}
public class NYPizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
switch (type)
{
case "cheese":
return new NYCheesePizza();
default:
return null;
}
}
}
public class KNPizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
switch (type)
{
case "cheese":
return new KNCheesePizza();
default:
return null;
}
}
}
pure Abstract factory pattern
public interface IIngredientFactory
{
IDough createDough();
ISauce createSauce();
}
public class NYIngredientFactory : IIngredientFactory
{
public IDough createDough()
{
return new NYDough();
}
public ISauce createSauce()
{
return new NYSauce();
}
}
public class KNIngredientFactory : IIngredientFactory
{
public IDough createDough()
{
return new KNDough();
}
public ISauce createSauce()
{
return new KNSauce();
}
}
public class Pizza
{
IDough Dough { get; set; }
ISauce Sauce { get; set; }
IIngredientFactory IngredientFactory { get; set; }
public Pizza(IIngredientFactory ingredientFactory)
{
IngredientFactory = ingredientFactory;
}
public void Prepare()
{
Dough = IngredientFactory.createDough();
Sauce = IngredientFactory.createSauce();
}
public void Bake() { }
public void Cut() { }
public void Box() { }
}
public interface IPizzaFactory
{
Pizza CreatePizza(string type);
}
public class NYPizzaFactory : IPizzaFactory
{
public Pizza CreatePizza(string type)
{
switch (type)
{
case "cheese":
return new Pizza(new NYIngredientFactory());
default:
return null;
}
}
}
public class KNPizzaFactory : IPizzaFactory
{
public Pizza CreatePizza(string type)
{
switch (type)
{
case "cheese":
return new Pizza(new KNIngredientFactory());
default:
return null;
}
}
}
public class PizzaStore
{
IPizzaFactory PizzaFactory { get; set; }
public PizzaStore(IPizzaFactory pizzaFactory)
{
PizzaFactory = pizzaFactory;
}
public void OrderPizza(string type)
{
Pizza pizza = PizzaFactory.CreatePizza(type);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
}
}
If I had used the patterns definitions I would have chosen a "Factory Method Pattern" for the PizzaStore
(since it only builds one type of object, Pizza) and the "Abstract Factory Pattern" for the IngredientFactory
. Anyway, another design principle, states that you should "favor composition over inheritance" which suggests that I should always use the "Abstract Factory Pattern".
My question is: What are the reasons I should choose the "Factory Method Pattern" in the first place?
EDIT
Let's take a look at the first implementation, the one that uses the Factory method pattern. Jesse van Assen suggested that this is a Template method pattern instead of a Factory method pattern. I'm not convinced it's right.
We can break down the first implementation in two parts: the first one that deals with Pizza
and the second one that deals with PizzaStore
.
1) in the first part Pizza
is the client that is dependent on some kind of concrete Dough and Sauce. In order to decouple Pizza from concrete objects I used, within the Pizza
class, reference to interfaces only (IDough
and ISauce
) and I let the Pizza
's subclasses decide which concrete Dough
and Sauce
choose. To me this fits perfectly with the definition of a Factory method pattern:
Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.
2) in the second part PizzaStore
is the client and it's dependent on concrete Pizza
. I applied the same principles discussed above.
So, to express better (I hope) what I don't really get is why is said that:
Factory Method pattern is responsible of creating products that belong to one family, while Abstract Factory pattern deals with multiple families of products.
As you see from my examples (provided they are right :-)) you can same stuff with both patterns.