Design Patterns - The Factory Method Pattern
24 Jun 2018Intent
“Defines an interface for creating an object, but let subclass decide which class to instantiate.The Factory Method lets a class defer instantiation it uses to subclasses “ - Gang of Four
Problem
A class needs to instantiate a derivation of another class, but doesn’t know which one. Factory Method allows a derived class to make the decision.
Solutions
A derived class makes the decision on which class to instantiate and how to instantiate it. The Factory Method pattern recommends replacing the direct object creation (using new
operator) with a call to special Factory Method without having to specify the exact class of the object that will be created. The constructor call should be moved inside that method.
- Define a separate operation (factory method) for creating an object.
- Create an object by calling a factory method
Participants
- Product - Interface for the type of object that the Factory Method creates.
- Concrete Product - Different implementations of the Product interface.
- Creator - Interface that defines the Factory Method. It declares a factory method that returns the Product type. This method can either be abstract or have some default implementation.
- Concrete Creator - It implements or overrides the base factory method, by creating and returning one of the *Concrete Product**
Implementation
Use a method in the abstract class that is abstract . The abstract class code refers of this method when it needs to instantiate a contained object but doesn’t know which particular object it needs.
Example
Pizza.java
package com.art.head_first.pizzastore;
import java.util.ArrayList;
/**
* Product
*/
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList<String> toppings = new ArrayList<>();
public void prepare() {
System.out.println("Prepare " + name);
System.out.println("Tossing dough..." + dough);
System.out.println("Adding sauce..." + sauce);
System.out.println("Adding toppings: ");
toppings.forEach(topping -> {
System.out.println("* " + topping);
});
}
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cut the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official pizzastore box");
}
public String getName() {
return name;
}
public String toString() {
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (String topping : toppings) {
display.append(topping + "\n");
}
return display.toString();
}
}
ChicagoPizza.java
package com.art.head_first.pizzastore;
public class ChicagoPizza extends Pizza {
@Override
void bake() {
System.out.println("Bake for 45 minutes at 425");
}
}
CaliforniaPizza.java
package com.art.head_first.pizzastore;
public class CaliforniaPizza extends Pizza{
}
ChicagoPizzaStore
package com.art.head_first.pizzastore;
import com.google.common.collect.Lists;
/**
* Concrete Creator
*/
public class ChicagoPizzaStore extends PizzaStore {
@Override
Pizza createPizza() {
ChicagoPizza chicagoPizza = new ChicagoPizza();
chicagoPizza.name = "Chicago Pizza";
chicagoPizza.sauce = "Marinara Sauce";
chicagoPizza.dough = "Deep Dish Dough";
chicagoPizza.toppings = Lists.newArrayList("Pepperoni", "Sausage");
return chicagoPizza;
}
}
CaliforniaPizzaStore.java
package com.art.head_first.pizzastore;
import com.google.common.collect.Lists;
/**
* Concrete Creator
*/
public class CaliforniaPizzaStore extends PizzaStore{
@Override
Pizza createPizza() {
CaliforniaPizza californiaPizza = new CaliforniaPizza();
californiaPizza.name = "California Pizza";
californiaPizza.dough = "Thin Crust";
californiaPizza.sauce = "Light Alfredo";
californiaPizza.toppings = Lists.newArrayList("Avocado", "Chicken", "Basil", "Sun-Dried Tomatoes");
return californiaPizza;
}
}
PizzaTestDrive.java
package com.art.head_first.pizzastore;
/**
* Test Application for Factory Method Design Pattern
*/
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore chicagoStore = new ChicagoPizzaStore();
CaliforniaPizzaStore californiaPizzaStore = new CaliforniaPizzaStore();
Pizza chicagoPizza = chicagoStore.orderPizza();
Pizza californiaPizza = californiaPizzaStore.orderPizza();
}
}
Output
---
Prepare Chicago Pizza
Tossing dough...Deep Dish Dough
Adding sauce...Marinara Sauce
Adding toppings:
* Pepperoni
* Sausage
Bake for 45 minutes at 425
Cut the pizza into diagonal slices
Place pizza in official pizzastore box
---
Prepare California Pizza
Tossing dough...Thin Crust
Adding sauce...Light Alfredo
Adding toppings:
* Avocado
* Chicken
* Basil
* Sun-Dried Tomatoes
Bake for 25 minutes at 350
Cut the pizza into diagonal slices
Place pizza in official pizzastore box