Factory Design Pattern


Intent

Define an interface for creating an object, but let subclasses decide which class
to instantiate. Factory Method lets a class defer instantiation to subclasses.

Also Known As

Virtual Constructor 

Explanation

Real world example

 Consider an example of using multiple database servers like SQL Server and Oracle. If you are developing an application using SQL Server database as backend, but in future need to change backend database to oracle, you will need to modify all your code, if you haven’t written your code following factory design pattern.

In plain words

It provides a way to delegate the instantiation logic to child classes.

Wikipedia says

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor. 

Structure

Participants

1. Product 
  •  defines the interface of objects the factory method creates.
2. ConcreteProduct 
  • implements the Product interface.
3. Creator (Application)
  • declares the factory method, which returns an object of type Product.Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object.
  • may call the factory method to create a Product object.
4. ConcreteCreator
  • overrides the factory method to return an instance.

Collaborations

  • Creator relies on its subclasses to define the factory method so that it returns an instance of the appropriate ConcreteProduct.

Source Code 


Let's create a simple Pizza Store application usingthe Factory pattern.
Step 1 : Createan abstract Pizza  class , which abstract pizza related data.

package headfirst.factory.pizzas;

import java.util.ArrayList;

abstract public class Pizza {
 String name;
 String dough;
 String sauce;
 ArrayList toppings = new ArrayList();

 public String getName() {
  return name;
 }

 public void prepare() {
  System.out.println("Preparing " + name);
 }

 public void bake() {
  System.out.println("Baking " + name);
 }

 public void cut() {
  System.out.println("Cutting " + name);
 }

 public void box() {
  System.out.println("Boxing " + name);
 }

 public String toString() {
  // code to display pizza name and ingredients
  StringBuffer display = new StringBuffer();
  display.append("---- " + name + " ----\n");
  display.append(dough + "\n");
  display.append(sauce + "\n");
  for (int i = 0; i < toppings.size(); i++) {
   display.append((String )toppings.get(i) + "\n");
  }
  return display.toString();
 }
}

Step 2 :  Create Concrete Pizza class - CheesePizza, ClamPizza,VeggiePizza and PepperoniPizza java class.

public class CheesePizza extends Pizza {
 public CheesePizza() {
  name = "Cheese Pizza";
  dough = "Regular Crust";
  sauce = "Marinara Pizza Sauce";
  toppings.add("Fresh Mozzarella");
  toppings.add("Parmesan");
 }
}

public class ClamPizza extends Pizza {
 public ClamPizza() {
  name = "Clam Pizza";
  dough = "Thin crust";
  sauce = "White garlic sauce";
  toppings.add("Clams");
  toppings.add("Grated parmesan cheese");
 }
}

public class VeggiePizza extends Pizza {
 public VeggiePizza() {
  name = "Veggie Pizza";
  dough = "Crust";
  sauce = "Marinara sauce";
  toppings.add("Shredded mozzarella");
  toppings.add("Grated parmesan");
  toppings.add("Diced onion");
  toppings.add("Sliced mushrooms");
  toppings.add("Sliced red pepper");
  toppings.add("Sliced black olives");
 }
}

public class PepperoniPizza extends Pizza {
 public PepperoniPizza() {
  name = "Pepperoni Pizza";
  dough = "Crust";
  sauce = "Marinara sauce";
  toppings.add("Sliced Pepperoni");
  toppings.add("Sliced Onion");
  toppings.add("Grated parmesan cheese");
 }
}
Step 3 : Create Factory Pattern class - SimplePizzaFactory java class.
public class SimplePizzaFactory {

 public Pizza createPizza(String type) {
  Pizza pizza = null;

  if (type.equals("cheese")) {
   pizza = new CheesePizza();
  } else if (type.equals("pepperoni")) {
   pizza = new PepperoniPizza();
  } else if (type.equals("clam")) {
   pizza = new ClamPizza();
  } else if (type.equals("veggie")) {
   pizza = new VeggiePizza();
  }
  return pizza;
 }
}
Step 4 : Let's test the Factory Pattern - PizzaTestDrive java class.
public class PizzaTestDrive {
 
 public static void main(String[] args) {
  SimplePizzaFactory factory = new SimplePizzaFactory();
  PizzaStore store = new PizzaStore(factory);

  Pizza pizza = store.orderPizza("cheese");
  System.out.println("We ordered a " + pizza.getName() + "\n");
 
  pizza = store.orderPizza("veggie");
  System.out.println("We ordered a " + pizza.getName() + "\n");
 }
}

Output : 

Preparing Cheese Pizza
Baking Cheese Pizza
Cutting Cheese Pizza
Boxing Cheese Pizza
We ordered a Cheese Pizza

Preparing Veggie Pizza
Baking Veggie Pizza
Cutting Veggie Pizza
Boxing Veggie Pizza
We ordered a Veggie Pizza

View source code Factory Design Pattern on my github repository :

Advantage of Factory Design Pattern

  • Factory Method Pattern allows the sub-classes to choose the type of objects to create.
  • It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code. That means the code interacts solely with the resultant interface or abstract class, so that it will work with any classes that implement that interface or that extends that abstract class.

Applicability

Use the Factory Method pattern when
  • a class can't anticipate the class of objects it must create
  • a class wants its subclasses to specify the objects it creates
  • classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate

Known uses

Comments