Search code examples
javareflectionfactory-patternopen-closed-principle

How to satisfy Open Closed Principle in Factory Pattern using Reflection?


I am trying to learn Object Oriented Design pattern using Head First Design Pattern. Here is one example of factory pattern from the book, where i want to add new pizza item without violating the open closed principle. In the given example code from the book, if i add new pizza item class, I need to modify the PizzaStore and PizzaOrder class. But I just want to add new Pizza Item without modifying other classes.

public class ChicagoPizzaStore extends PizzaStore {

Pizza createPizza(String item) {
        if (item.equals("cheese")) {
                return new ChicagoStyleCheesePizza();
        } else if (item.equals("veggie")) {
                return new ChicagoStyleVeggiePizza();
        } else if (item.equals("clam")) {
                return new ChicagoStyleClamPizza();
        } 
            else return null;
}

}

This pizzaStore class is to create and order the pizza.

public abstract class PizzaStore {

    abstract Pizza createPizza(String item);

public Pizza orderPizza(String type) {
    Pizza pizza = createPizza(type);
    System.out.println("--- Making a " + pizza.getName() + " ---");
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

}

This is the abstract 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));
    }
}

This class is used to take the order from the customer.

 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() + "\n");
    }
}

This is my new pizza item class. I want to order this pizza item without modifying chicagoPizzaStore and testDrive class:

public class ChicagoStyleClamPizza extends Pizza {
    public ChicagoStyleClamPizza() {
        name = "Chicago Style Clam Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Shredded Mozzarella Cheese");
        toppings.add("Frozen Clams from Chesapeake Bay");
    }

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

Solution

  • The point of Factory Method design pattern is to make client and concrete product loosely coupled. Client interacts with only interface or base class. Thus in future if you need to add new concrete product class (in your case Pizza), the new class should not result in changes in the client code (in your case PizzaTestDrive). For adding a new product (Pizza), you should only need to modify Concrete Factory class (in your case ChicagoPizzaStore).

    I think your implementation of Factory Method design pattern is correct. For adding a new Pizza, the client code is not going to change, only Concrete Factory class is changing.