Design Patterns - The Factory Method Pattern

example-observer-design-pattern

Intent

“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.

observer-design-pattern

Example

example-observer-design-pattern

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