The standard way of creating an object is to instantiate a concrete class directly with the new operator:
SomeClass sc = new SomeClass();
One of the drawbacks of using the new operator to create an object is the need to specify the type of object to create. Specifically, it creates a dependency between your code and the class or type of object created. Sometimes a more general solution is needed, one that allows control over when an instance of an object is created but leaves open or delegates to another class the specific type of object to create.
Decoupling object creation from object use results in code that is more flexible and extendable.
Also, the advice “program to an interface, not an implementation” also applies to object creation. You could create an object with the new operator.
class ClientCodeC{
public clientCodeC(){
SupportingClass sc = new SupportingClass();
}
}
However, the reference to concrete class SupportingClass at line 3 is an example of programming to an implementation. If there is nothing about clientCodeC that requires an instance of SupportingClass, it is usually better to program to an abstract interface that will result in the creation of an instance of SupportingClass or another type that is compatible with the client code.
But how do we do that? That is precisely the problem solved by the Factory Method design pattern.
The Factory design pattern has four main components. The class Creator declares a factory method createProduct(). createProduct() returns an object of type Product. Subclasses of Creator override the factory method to create and return a concrete instance of Product.
There are many forms. Here’s one.
Here’s another.
Notice how it differs from the structure diagram in the previous example. In the previous example there is a one-to-many relationship between concrete creators and concrete products. With iteration in Java there is a one-to-one relationship between concrete collection classes and concrete iterators. Both are valid forms of the pattern.
But what happens when we have multiple store franchises. Let’s say that we have two stores, one wants to make NY style pizzas and the other wants to make Chicago style pizzas.
Now we’re in a situation where we are going to need either a much more complex factory or two different factories to make the two different styles of pizza or we’ll have to put all the logic for creating the different pizzas back into the store. All this options make for a more complicated code, and many more places where we’ll have to change code if we add new pizza types or change a topping.
The current implementation, below, also violates the open/closed principle. There is no way to extend the current solution to work with other credit card processing services without modifying the code.
The store needs to use the same order pizza method so that the prepare, bake, cut, box the pizzas in the same way, but have the flexibility of creating different styles of pizza objects, one creating NY style pizzas while the other creates Chicago style pizzas. What we want is to have two different kinds of pizza stores that use the same time testing algorithm to make pizzas but that can make two different kinds of pizzas. But without being dependent on the concrete types of pizzas on any way.
To create our store franchises, we’ll change the design to use the Factory Method Pattern.
The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Let’s see what that means by looking at the new design for the pizza store.
First we’re going to change the pizza store class so that it is an abstract class. All the pizza stores in the franchise will extend this class. To make sure that all the pizza stores use the same method for preparing pizzas for customers, in other words the same algorithm, the pizza store abstract class will implement the order pizza method. This is the shared code all the stores use for preparing the pizza, no matter what store we’re in and what type of pizza it is.
However, the two pizza stores that extend this class, NY store and Chicago store, will implement their own create pizza methods. That way each store gets to decide what kind of pizzas it will make. The NY store will make NY style pizzas while the Chicago store will make Chicago style pizzas. This is what is meant in the factory method pattern definition, when we say the factory method pattern lets a class defer instantiation to subclasses. Here the abstract class pizza store is deferring instantiation of concrete pizzas to the individual pizza store that extend it.
The pizza class is basically going to be the same, but now we’re going to have many different types of pizzas. A set of pizzas for the NY style pizza store and a set of pizzas for the Chicago style pizza store. The NY pizza store will be responsible for creating the NY style pizza and the Chicago style pizza store will be responsible for creating the Chicago style pizzas.
To create a pizza, we’ll first instantiate the kind of store that we want. Imaging choosing between walking into a NY style pizza store or a Chicago style pizza store. Once we’re in the store, we can order a pizza. Remember this method is implemented by the abstract class pizza store. So, no matter which pizza store we’re in when we make an order, we’re guaranteed to get the same brilliant pizza making algorithm to produce quality pizzas.
The first step in the order pizza algorithm is to create a pizza. The create pizza method is implemented by the individual stores. So, if we’re in a NY style pizza store we’ll get the method implemented by that store. We pass the type of pizza to the create pizza method. This method creates the right type of pizza based on the type and once it is returned to the order pizza method in the store, the order pizza method can prepare the pizza to the customer.
Here’s our main class.
Recall that in the Simple Factory idiom, we first created a factory and then passed the factory to the store. We no longer need the factory because the pizza stores are created the pizzas directly. Remember that the pizza stores order pizza method, implemented in the pizza store abstract class creates the kind of pizzas that we want depending on which store we call the method on.
PizzaStore is implemented as a Factory Method because we want to be able to create a product that varies by region. With the Factory Method, each region gets its own concrete factory that knows how to make pizzas which are appropriate for the area.
Works Cited
Burris, Eddie. “Chapter 8 Factory Method.” Programming in the Large with Design Patterns. Leawood, Kan: Pretty Print, 2012. 110-122. Print.
Freeman, Eric, and Elisabeth Freeman. “Chapter 4. The Factory Method Pattern: Baking with OO Goodness.” Head First Design Patterns. Sebastopol, CA: O’Reilly Media, 2005. N. pag. Print
From the blog CS@Worcester – thewisedevloper by thewisedeveloper and used with permission of the author. All other rights reserved by the author.