Overview

Creating Objects

Duck duck = new MallardDuck();
Duck duck;

if (picnic) duck = new MallardDuck();
else if (hunting) duck = new DecoyDuck();
else if (inBathTub) duck = new RubberDuck();

Factory Patterns

Example

Original Code

Pizza orderPizza(String type) {
    Pizza pizza;
    if (type.equals("cheese"))
        pizza = new CheesePizza();
    else if (type.equals("greek"))
        pizza = new GreekPizza();
    else if (type.equals("pepperoni"))
        pizza = new PepperoniPizza();

    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();

    return pizza;
}

Pizza types are changing!

Pizza orderPizza(String type) {
Pizza pizza;
if (type.equals("cheese"))
    pizza = new CheesePizza();

// changed
else if (type.equals("clam"))
    pizza = new ClamPizza();
else if (type.equals("pepperoni"))
    pizza = new PepperoniPizza();

    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();

    return pizza;
}

Building a Simple Factory

public class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza;
        if (type.equals("cheese"))
            pizza = new CheesePizza();
        else if (type.equals("greek"))
            pizza = new GreekPizza();
        else if (type.equals("pepperoni"))
            pizza = new PepperoniPizza();

        return pizza;
    }
}

Revising PizzaStore class using the Simple Factory

pubilc class PizzaStore {
    SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = factory.createPizza(type); // use SimplePizzaFactory

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

Simple Factory (not an official pattern)

diagram

Franchising the pizza store

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.order(“Veggie”);

ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore chicagoStore = new PizzaStore(chicagoFactory);
chicagoStore.order(“Veggie”);

Factory Method Pattern

Requirement Change

public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }

    protected abstract Pizza createPizza(String type);
}

Factory Method

Allowing the subclasses to decide

diagram
// NYPizzaStore
public Pizza createPizza(String type) {
    Pizza pizza;
    if (type.equals(“cheese”)) {
        pizza = new NYStyleCheesePizza();
    } else if (type.equals(“veggie”)) {
        pizza = new NYStyleVeggiePizza();
    }

    return pizza;
}
// ChicagoPizzaStore
public Pizza createPizza(String type) {
    Pizza pizza;
    if (type.equals(“cheese”)) {
        pizza = new ChicagoStyleCheesePizza();
    } else if (type.equals(“veggie”)) {
        pizza = new ChicagoStyleVeggiePizza();
    }
    return pizza;
}

Ordering a pizza using the Factory Method

  1. Need an instance of PizzaStore.
    PizzaStore nyPizzaStore = new NYPizzaStore();
    
  2. Call orderPizza().
    nyPizzaStore.orderPizza(“cheese”);
    
  3. orderPizza() calls createPizza().
    Pizza pizza = createPizza(“cheese”);
    
  4. orderPizza() now prepare, bake, cut and box the pizza.
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    

Implementing Pizza class

public abstract class Pizza {
    String name;
    String dough;
    String sauce;

    ArrayList toppings = new ArrayList();

    void prepare(){
        System.out.println(“Preparing “ + name);
        System.out.println(“Tossing dough...”);
        System.out.println(“Adding sauce...”);
        System.out.println(“Adding toppings: “);

        for (int i = 0; i < toppings.size(); i++)
            System.out.println(“ “ + toppings.get(i));
    }

    void bake(){
        System.out.println(“Bake for 25 minutes at 350”);
    }

    void cut(){
        System.out.println(“Cutting the pizza into diagonal slices”);
    }

    void box(){
        System.out.println(“Place pizza in official PizzaStore box”);
    }
}

Subclasses of Pizza

public class NYStyleCheesePizza extends Pizza {
    public NYStyleCheesePizza(){
        name = “NY Style Sauce and Cheese Pizza”;
        dough = “Thin Crust Dough”;
        sauce = “Marinara Sauce”;
        toppings.add(“Grated Reggiano Cheese”);
    }
}

public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza(){
        name = “Chicago Style Deep Dish and Cheese Pizza”;
        dough = “Extra Thick Crust Dough”;
        sauce = “Plum Tomato Sauce”;
        toppings.add(“Shredded Mozzarella Cheese”);
    }

    void cut(){
        System.out.println(“Cutting the pizza into square slices”);
    }
}

Test Drive

public class PizzaTestDrive {
    public static void main(String[] args){
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();

        Pizza pizza = nyStore.orderPizza(“cheese”);
        System.out.println(“Ethan ordered a “ + pizza.getName());

        Pizza pizza = chicagoStore.orderPizza(“cheese”);
        System.out.println(“Joel ordered a “ + pizza.getName());
    }
}

Applying Factory Method Pattern

diagram

Factory Method Pattern

diagram

A very dependent PizzaStore (bad design)

public class DependentPizzaStore {
    public Pizza createPizza(String style, String type) {
        Pizza pizza = null;

        if (style.equals("NY")) {
            if (type.equals("cheese")) {
                pizza = new NYStyleCheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new NYStyleVeggiePizza();
            }
        } else if (style.equals("Chicago")) {
            if (type.equals("cheese")) {
                pizza = new ChicagoStyleCheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new ChicagoStyleVeggiePizza();
            }
        } else {
            System.out.println("Error: invalid type of pizza");
            return null;
        }

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

Dependent PizzaStore VS Factory Method

diagram

Design Principle: Dependency Inversion Principle

Factory Method Pattern