Factory method pattern is a creational design pattern that provides an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Problem
Lets imagine we are creating a pizza store and we have multiple type of pizzas we serve to our customers. At first the only pizza type our store is baking is the four cheese pizza. After a while many of our customers requests for a bigger variety of pizza and we decide to add peperoni and Greek pizzas to our menu. These are great news but what about our code?
Solution
Here is where Factory Method Pattern comes in handy. The pattern suggests that we replace any direct construction calls with calls to a factory method.
Implementation
The first thing we are going to create is the Pizza abstract class.
public abstract class Pizza
{
public string Name { get; set; }
public List<string> Ingredients { get; set; }
public PizzaType Type{ get; set; }
}
With that out of the way we are going to create our concrete classes implementing the abstract class
class FourCheesePizza : Pizza
{
public FourCheesePizza()
{
Type = PizzaType.FourCheese;
Name = "Cheese passion";
Ingredients = new List<string>
{
"Parmigiano Cheese",
"Gorgonzola Cheese",
"Ricotta Cheese",
"Taleggio Cheese",
"Tomato"
};
}
}
class GreekPizza : Pizza
{
public GreekPizza()
{
Name = "The Greek freak";
Type = PizzaType.Greek;
Ingredients = new List<string>
{
"Spinach",
"Olives",
"Feta Cheese",
"Onion",
"Red Peppers"
};
}
}
class PepperoniPizza : Pizza
{
public PepperoniPizza()
{
Name = "Pepperoni lovers";
Type = PizzaType.Pepperoni;
Ingredients = new List<string>
{
"Basil",
"Peperoni",
"Garlic",
"Tomato",
"Mozzarella Cheese"
};
}
}
Next step is to create the actual factory interface and it’s implementation
interface IPizzaFactory
{
Pizza CreatePizza(PizzaType type);
}
class PizzaFactory : IPizzaFactory
{
public Pizza CreatePizza(PizzaType type)
{
switch (type)
{
case PizzaType.FourCheese:
return new FourCheesePizza();
case PizzaType.Pepperoni:
return new PepperoniPizza();
case PizzaType.Greek:
return new GreekPizza();
default:
return null;
}
}
}
And now we can use the factory to get a pizza object by passing the pizza type information.
static void Main(string[] args)
{
var pizza = OrderPizza(PizzaType.Greek);
Console.WriteLine("Pizza name: " + pizza.Name);
Console.WriteLine("---------------------");
Console.WriteLine("Ingredients");
Console.WriteLine("---------------------");
Console.WriteLine(string.Join(Environment.NewLine, pizza.Ingredients));
Console.ReadKey();
}
static Pizza OrderPizza(PizzaType type)
{
IPizzaFactory factory = new PizzaFactory();
return factory.CreatePizza(type);
}