The Simple Factory Idiom

When you see “new”, think “concrete”

When you use “new”, you are instantiating a concrete class - an implementation, not an interface. Tying your code to a concrete class can make it more fragile and less flexible.

When you have a whole set of related concrete classed, often you are forced to write code like this:

Duck duck;

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

Here, we have several concrete classes being instantiated, and the decision of which to instantiate is made at runtime depending on some set of conditions.

When it comes time for changes or extensions, you will have to reopen this code and examine what needs to be added (or deleted). Often, this kind of code ends up in several parts of the application making maintenance and updates more difficult and error-prone.

Design principle: The Open-Closed design principle

By coding to an interface, you can insulate yourself from a lot of changes that might happen to a system down the road. If your code is written to an interface, then it will work with any new classes implementing that interface through polymorphism. However, when you have code that makes use of lots of concrete classes, you are looking for trouble because that code may have to be changed as new concrete classes are added. In other words, your code will not be closed for modification. To extend it with new concrete types, you will have to reopen it.

Design principle: Encapsulate what varies

Identify the aspects that vary and separate them from what stays the same.

Pizza Store

Without using a factory

Without using a factory, the code for pizza store will look something like this:

 public class PizzaStore {

        public 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;
        }

}

Now, you want to add new items to the menu - Clam Pizza, Veggie Pizza and remove Greek Pizza from the menu.

 public class PizzaStore {

        public Pizza orderPizza(String type) {
                Pizza pizza;

                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();
                }

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

                return pizza;
        }

}

Clearly, dealing with which concrete class is instantiated is messing up our orderPizza() method and preventing it from being closed for modification. Now that we know what is varying and what is not, we can encapsulate it.

Encapsulating object creation

We would be better off moving the object creation out of the orderPizza() method. Lets take the creation code and move it out into another object that is only going to be concerned with creating pizzas. Define a class tthat encapsulates the object creation for all pizzas.

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;
        }
}

The name of this new object (createPizza()) is : Factory.

Factories handle the details of object creation.

Now, orderPizza() just becomes a client of that object. Any time it needs a pizza, it asks the pizza factory to make one. The orderPizza() doesn’t need to know about Greek vs Clam or any other type of pizzas. All it needs is, it gets a pizza that implements the Pizza interface so that it can call prepare(), bake(), cut() and box().

With this, PizzaStore looks like this:

public class PizzaStore {
        SimplePizzaFactory factory;

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

        public Pizza orderPizza(String type) {
                Pizza pizza;

                pizza = factory.createPizza(type);

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

                return pizza;
        }

}

Now, the class diagram of PizzaStore looks like this:

┌──────────────────┐        ┌──────────────────────┐
│                  │        │                      │        ┌──────────────────┐
│   PizzaStore     ├───────►│  SimplePizzaFactory  │        │      Pizza       │
│                  │        │                      ├───────►│                  │
├──────────────────┤        ├──────────────────────┤        ├──────────────────┤
│                  │        │                      │        │                  │
│   orderPizza()   │        │  createPizza()       │        │     prepare()    │
│                  │        │                      │        │                  │
└──────────────────┘        └──────────────────────┘        │     bake()       │
                                                            │                  │
                                                            │                  │
                                                            │     cut()        │
                                                            │                  │◄──────────────────────────────────────┐
                                                            │                  │                                       │
                                                      ┌────►│     box()        │                                       │
                                                      │     │                  │◄───────────────┐                      │
                                                      │     └──────────────────┘                │                      │
                                                      │                ▲                        │                      │
                                                      │                │                        │                      │
                                                      │                │                        │                      │
                                               ┌──────┴───────┐    ┌───┴──────────┐          ┌──┴──────────┐      ┌────┴────────────┐
                                               │              │    │              │          │             │      │                 │
                                               │ CheesePizza  │    │ VeggiePizza  │          │  ClamPizza  │      │ PepperoniPizza  │
                                               ├──────────────┤    ├──────────────┤          ├─────────────┤      ├────────────────┬┤
                                               │              │    │              │          │             │      │                 │
                                               │              │    │              │          │             │      │                 │
                                               │              │    │              │          │             │      │                 │
                                               │              │    │              │          │             │      │                 │
                                               └──────────────┘    └──────────────┘          └─────────────┘      └─────────────────┘

We have only seen the orderPizza() method. However, there may be a PizzaShopMenu class that uses the factory to get pizzas for their current description and price. We might also have a HomeDelivery class that handles pizzas in a different way than our PizzaShop class but is also a client of the factory.

By encapsulating the pizza creating in one class, we have only one place to make modifications when the implementation changes.

In some similar designs, a factory like this is defined as a static method. Why is that and what is the difference?

Defining a simple factory as a static method is a common technique and is often called a static factory. Why use a static method? Because you don’t need to instantiate an object to make use of the create method. But remember that it also has the disadvantage that you can’t subclass and change the behavior of the create method.

The Simple Factory idiom

The Simple Factory isn’t actually a Design Pattern; it is more of a programming idiom. Some developers do mistake this idiom for the “Factory Pattern”.

The Simple Factory is a warm up to explore two heavy-duty patterns that are both factories.


Links to this note