Chapter 4. The Factory Pattern: Baking with OO Goodness
Get ready to bake some loosely coupled OO designs. There is more to making objects than just using the new operator. You’ll learn that instantiation is an activity that shouldn’t always be done in public and can often lead to coupling problems. And you don’t want that, do you? Find out how Factory Patterns can help save you from embarrassing dependencies.
When you see “new,” think “concrete.”
Yes, when you use new you are certainly instantiating a concrete class, so that’s definitely an implementation, not an interface. And it’s a good question; you’ve learned that tying your code to a concrete class can make it more fragile and less flexible.
When you have a whole set of related concrete classes, often you’re forced to write code like this:
Here we’ve got several concrete classes being instantiated, and the decision of which to instantiate is made at runtime depending on some set of conditions.
When you see code like this, you know that when it comes time for changes or extensions, you’ll 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.
What’s wrong with “new”?
Technically there’s nothing wrong with new. After all, it’s a fundamental part of Java. The real culprit is our old friend CHANGE and how change impacts our use of new.
By coding to an interface, you know you can insulate yourself from a lot of changes that might happen to a system down the road. Why? 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’re looking for trouble because that code may have to be changed as new concrete classes are added. So, in other words, your code will not be “closed for modification.” To extend it with new concrete types, you’ll have to reopen it.
Note
Remember that designs should be “open for extension but closed for modification” - see Chapter 3 for a review.
So what can you do? It’s times like these that you can fall back on OO Design Principles to look for clues. Remember, our first principle deals with change and guides us to identify the aspects that vary and separate them from what stays the same.
Brain Power
How might you take all the parts of your application that instantiate concrete classes and separate or encapsulate them from the rest of your application?
Identifying the aspects that vary
Let’s say you have a pizza shop, and as a cutting-edge pizza store owner in Objectville you might end up writing some code like this:
But you need more than one type of pizza...
So then you’d add some code that determines the appropriate type of pizza and then goes about making the pizza:
But the pressure is on to add more pizza types
You realize that all of your competitors have added a couple of trendy pizzas to their menus: the Clam Pizza and the Veggie Pizza. Obviously you need to keep up with the competition, so you’ll add these items to your menu. And you haven’t been selling many Greek Pizzas lately, so you decide to take that off the menu:
Clearly, dealing with which concrete class is instantiated is really messing up our orderPizza() method and preventing it from being closed for modification. But now that we know what is varying and what isn’t, it’s probably time to encapsulate it.
Encapsulating object creation
So now we know we’d be better off moving the object creation out of the orderPizza() method. But how? Well, what we’re going to do is take the creation code and move it out into another object that is only going to be concerned with creating pizzas.
We’ve got a name for this new object: we call it a Factory.
Factories handle the details of object creation. Once we have a SimplePizzaFactory, our orderPizza() method just becomes a client of that object. Any time it needs a pizza it asks the pizza factory to make one. Gone are the days when the orderPizza() method needs to know about Greek versus Clam pizzas. Now the orderPizza() method just cares that it gets a pizza that implements the Pizza interface so that it can call prepare(), bake(), cut(), and box().
We’ve still got a few details to fill in here; for instance, what does the orderPizza() method replace its creation code with? Let’s implement a simple factory for the pizza store and find out...
Building a simple pizza factory
We’ll start with the factory itself. What we’re going to do is define a class that encapsulates the object creation for all pizzas. Here it is...
Reworking the PizzaStore class
Now it’s time to fix up our client code. What we want to do is rely on the factory to create the pizzas for us. Here are the changes:
Brain Power
The Simple Factory defined
The Simple Factory isn’t actually a Design Pattern; it’s more of a programming idiom. But it is commonly used, so we’ll give it a Head First Pattern Honorable Mention. Some developers do mistake this idiom for the “Factory Pattern,” so the next time there is an awkward silence between you and another developer, you’ve got a nice topic to break the ice.
Just because Simple Factory isn’t a REAL pattern doesn’t mean we shouldn’t check out how it’s put together. Let’s take a look at the class diagram of our new Pizza Store:
Think of Simple Factory as a warm up. Next, we’ll explore two heavy-duty patterns that are both factories. But don’t worry, there’s more pizza to come!
Note
*Just another reminder: in design patterns, the phrase “implement an interface” does NOT always mean “write a class that implements a Java interface, by using the ‘implements’ keyword in the class declaration.” In the general use of the phrase, a concrete class implementing a method from a supertype (which could be a class OR interface) is still considered to be “implementing the interface” of that supertype.
Franchising the pizza store
Your Objectville PizzaStore has done so well that you’ve trounced the competition and now everyone wants a PizzaStore in their own neighborhood. As the franchiser, you want to ensure the quality of the franchise operations and so you want them to use your time-tested code.
But what about regional differences? Each franchise might want to offer different styles of pizzas (New York, Chicago, and California, to name a few), depending on where the franchise store is located and the tastes of the local pizza connoisseurs.
We’ve seen one approach...
If we take out SimplePizzaFactory and create three different factories—NYPizzaFactory, ChicagoPizzaFactory and CaliforniaPizzaFactory—then we can just compose the PizzaStore with the appropriate factory and a franchise is good to go. That’s one approach.
Let’s see what that would look like...
But you’d like a little more quality control...
So you test-marketed the SimpleFactory idea, and what you found was that the franchises were using your factory to create pizzas, but starting to employ their own home-grown procedures for the rest of the process: they’d bake things a little differently, they’d forget to cut the pizza and they’d use third-party boxes.
Rethinking the problem a bit, you see that what you’d really like to do is create a framework that ties the store and the pizza creation together, yet still allows things to remain flexible.
In our early code, before the SimplePizzaFactory, we had the pizza-making code tied to the PizzaStore, but it wasn’t flexible. So, how can we have our pizza and eat it too?
A framework for the pizza store
There is a way to localize all the pizza-making activities to the PizzaStore class, and yet give the franchises freedom to have their own regional style.
What we’re going to do is put the createPizza() method back into PizzaStore, but this time as an abstract method, and then create a PizzaStore subclass for each regional style.
First, let’s look at the changes to the PizzaStore:
Now we’ve got a store waiting for subclasses; we’re going to have a subclass for each regional type (NYPizzaStore, ChicagoPizzaStore, CaliforniaPizzaStore) and each subclass is going to make the decision about what makes up a pizza. Let’s take a look at how this is going to work.
Allowing the subclasses to decide
Remember, the PizzaStore already has a well-honed order system in the orderPizza() method and you want to ensure that it’s consistent across all franchises.
What varies among the regional PizzaStores is the style of pizzas they make—New York Pizza has thin crust, Chicago Pizza has thick, and so on—and we are going to push all these variations into the createPizza() method and make it responsible for creating the right kind of pizza. The way we do this is by letting each subclass of PizzaStore define what the createPizza() method looks like. So, we will have a number of concrete subclasses of PizzaStore, each with its own pizza variations, all fitting within the PizzaStore framework and still making use of the well-tuned orderPizza() method.
Well, think about it from the point of view of the PizzaStore’s orderPizza() method: it is defined in the abstract PizzaStore, but concrete types are only created in the subclasses.
Now, to take this a little further, the orderPizza() method does a lot of things with a Pizza object (like prepare, bake, cut, box), but because Pizza is abstract, orderPizza() has no idea what real concrete classes are involved. In other words, it’s decoupled!
When orderPizza() calls createPizza(), one of your subclasses will be called into action to create a pizza. Which kind of pizza will be made? Well, that’s decided by the choice of pizza store you order from, NYStylePizzaStore or ChicagoStylePizzaStore.
So, is there a real-time decision that subclasses make? No, but from the perspective of orderPizza(), if you chose a NYStylePizzaStore, that subclass gets to determine which pizza is made. So the subclasses aren’t really “deciding”—it was you who decided by choosing which store you wanted—but they do determine which kind of pizza gets made.
Let’s make a PizzaStore
Being a franchise has its benefits. You get all the PizzaStore functionality for free. All the regional stores need to do is subclass PizzaStore and supply a createPizza() method that implements their style of Pizza. We’ll take care of the big three pizza styles for the franchisees.
Here’s the New York regional style:
Note
* Note that the orderPizza() method in the superclass has no clue which Pizza we are creating; it just knows it can prepare, bake, cut, and box it!
Once we’ve got our PizzaStore subclasses built, it will be time to see about ordering up a pizza or two. But before we do that, why don’t you take a crack at building the Chicago Style and California Style pizza stores on the next page.
Declaring a factory method
With just a couple of transformations to the PizzaStore we’ve gone from having an object handle the instantiation of our concrete classes to a set of subclasses that are now taking on that responsibility. Let’s take a closer look:
So how do they order?
① First, Joel and Ethan need an instance of a PizzaStore. Joel needs to instantiate a ChicagoPizzaStore and Ethan needs a NYPizzaStore.
② With a PizzaStore in hand, both Ethan and Joel call the orderPizza() method and pass in the type of pizza they want (cheese, veggie, and so on).
③ To create the pizzas, the createPizza() method is called, which is defined in the two subclasses NYPizzaStore and ChicagoPizzaStore. As we defined them, the NYPizzaStore instantiates a NY style pizza, and the ChicagoPizzaStore instantiates a Chicago style pizza. In either case, the Pizza is returned to the orderPizza() method.
④ The orderPizza() method has no idea what kind of pizza was created, but it knows it is a pizza and it prepares, bakes, cuts, and boxes it for Ethan and Joel.
We’re just missing one thing: PIZZA!
Our PizzaStore isn’t going to be very popular without some pizzas, so let’s implement them
It’s finally time to meet the Factory Method Pattern
All factory patterns encapsulate object creation. The Factory Method Pattern encapsulates object creation by letting subclasses decide what objects to create. Let’s check out these class diagrams to see who the players are in this pattern:
Another perspective: parallel class hierarchies
We’ve seen that the factory method provides a framework by supplying an orderPizza() method that is combined with a factory method. Another way to look at this pattern as a framework is in the way it encapsulates product knowledge into each creator.
Let’s look at the two parallel class hierarchies and see how they relate:
Factory Method Pattern defined
It’s time to roll out the official definition of the Factory Method Pattern:
Note
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.
As with every factory, the Factory Method Pattern gives us a way to encapsulate the instantiations of concrete types. Looking at the class diagram below, you can see that the abstract Creator gives you an interface with a method for creating objects, also known as the “factory method.” Any other methods implemented in the abstract Creator are written to operate on products produced by the factory method. Only subclasses actually implement the factory method and create products.
As in the official definition, you’ll often hear developers say that the Factory Method lets subclasses decide which class to instantiate. They say “decide” not because the pattern allows subclasses themselves to decide at runtime, but because the creator class is written without knowledge of the actual products that will be created, which is decided purely by the choice of the subclass that is used.
A very dependent PizzaStore
Looking at object dependencies
When you directly instantiate an object, you are depending on its concrete class. Take a look at our very dependent PizzaStore one page back. It creates all the pizza objects right in the PizzaStore class instead of delegating to a factory.
If we draw a diagram representing that version of the PizzaStore and all the objects it depends on, here’s what it looks like:
The Dependency Inversion Principle
It should be pretty clear that reducing dependencies to concrete classes in our code is a “good thing.” In fact, we’ve got an OO design principle that formalizes this notion; it even has a big, formal name: Dependency Inversion Principle.
Note
Yet another phrase you can use to impress the execs in the room! Your raise will more than offset the cost of this book, and you’ll gain the admiration of your fellow developers.
Here’s the general principle:
At first, this principle sounds a lot like “Program to an interface, not an implementation,” right? It is similar; however, the Dependency Inversion Principle makes an even stronger statement about abstraction. It suggests that our high-level components should not depend on our low-level components; rather, they should both depend on abstractions.
Note
A “high-level” component is a class with behavior defined in terms of other, “low-level” components.
For example, PizzaStore is a high-level component because its behavior is defined in terms of pizzas - it creates all the different pizza objects, and prepares, bakes, cuts, and boxes them, while the pizzas it uses are low-level components.
But what the heck does that mean?
Well, let’s start by looking again at the pizza store diagram on the previous page. PizzaStore is our “high-level component” and the pizza implementations are our “low-level components,” and clearly the PizzaStore is dependent on the concrete pizza classes.
Now, this principle tells us we should instead write our code so that we are depending on abstractions, not concrete classes. That goes for both our high-level modules and our low-level modules.
But how do we do this? Let’s think about how we’d apply this principle to our Very Dependent PizzaStore implementation...
Applying the Principle
Now, the main problem with the Very Dependent PizzaStore is that it depends on every type of pizza because it actually instantiates concrete types in its orderPizza() method.
While we’ve created an abstraction, Pizza, we’re nevertheless creating concrete Pizzas in this code, so we don’t get a lot of leverage out of this abstraction.
How can we get those instantiations out of the orderPizza() method? Well, as we know, the Factory Method allows us to do just that.
So, after we’ve applied the Factory Method, our diagram looks like this:
After applying the Factory Method, you’ll notice that our high-level component, the PizzaStore, and our low-level components, the pizzas, both depend on Pizza, the abstraction. Factory Method is not the only technique for adhering to the Dependency Inversion Principle, but it is one of the more powerful ones.
Where’s the “inversion” in Dependency Inversion Principle?
The “inversion” in the name Dependency Inversion Principle is there because it inverts the way you typically might think about your OO design. Look at the diagram on the previous page. Notice that the low-level components now depend on a higher level abstraction. Likewise, the high-level component is also tied to the same abstraction. So, the top-to-bottom dependency chart we drew a couple of pages back has inverted itself, with both high-level and low-level modules now depending on the abstraction.
Let’s also walk through the thinking behind the typical design process and see how introducing the principle can invert the way we think about the design...
Inverting your thinking...
Okay, so you need to implement a PizzaStore. What’s the first thought that pops into your head? | |
Right, you start at the top and follow things down to the concrete classes. But, as you’ve seen, you don’t want your store to know about the concrete pizza types, because then it’ll be dependent on all those concrete classes! Now, let’s “invert” your thinking... instead of starting at the top, start at the Pizzas and think about what you can abstract. | |
Right! You are thinking about the abstraction Pizza. So now, go back and think about the design of the Pizza Store again. Close. But to do that you’ll have to rely on a factory to get those concrete classes out of your Pizza Store. Once you’ve done that, your different concrete pizza types depend only on an abstraction and so does your store. We’ve taken a design where the store depended on concrete classes and inverted those dependencies (along with your thinking). |
A few guidelines to help you follow the Principle...
The following guidelines can help you avoid OO designs that violate the Dependency Inversion Principle:
No variable should hold a reference to a concrete class.
No class should derive from a concrete class.
No method should override an implemented method of any of its base classes.
You’re exactly right! Like many of our principles, this is a guideline you should strive for, rather than a rule you should follow all the time. Clearly, every single Java program ever written violates these guidelines!
But, if you internalize these guidelines and have them in the back of your mind when you design, you’ll know when you are violating the principle and you’ll have a good reason for doing so. For instance, if you have a class that isn’t likely to change, and you know it, then it’s not the end of the world if you instantiate a concrete class in your code. Think about it; we instantiate String objects all the time without thinking twice. Does that violate the principle? Yes. Is that okay? Yes. Why? Because String is very unlikely to change.
If, on the other hand, a class you write is likely to change, you have some good techniques like Factory Method to encapsulate that change.
Meanwhile, back at the PizzaStore...
The design for the PizzaStore is really shaping up: it’s got a flexible framework and it does a good job of adhering to design principles.
Now, the key to Objectville Pizza’s success has always been fresh, quality ingredients, and what you’ve discovered is that with the new framework your franchises have been following your procedures, but a few franchises have been substituting inferior ingredients in their pies to lower costs and increase their margins. You know you’ve got to do something, because in the long term this is going to hurt the Objectville brand!
Ensuring consistency in your ingredients
So how are you going to ensure each franchise is using quality ingredients? You’re going to build a factory that produces them and ships them to your franchises!
Now there is only one problem with this plan: the franchises are located in different regions and what is red sauce in New York is not red sauce in Chicago. So, you have one set of ingredients that needs to be shipped to New York and a different set that needs to be shipped to Chicago. Let’s take a closer look:
Families of ingredients...
New York uses one set of ingredients and Chicago another. Given the popularity of Objectville Pizza, it won’t be long before you also need to ship another set of regional ingredients to California, and what’s next? Seattle?
For this to work, you are going to have to figure out how to handle families of ingredients.
Building the ingredient factories
Now we’re going to build a factory to create our ingredients; the factory will be responsible for creating each ingredient in the ingredient family. In other words, the factory will need to create dough, sauce, cheese, and so on... You’ll see how we are going to handle the regional differences shortly.
Let’s start by defining an interface for the factory that is going to create all our ingredients:
Note
If we’d had some common “machinery” to implement in each instance of factory, we could have made this an abstract class instead...
Here’s what we’re going to do:
① Build a factory for each region. To do this, you’ll create a subclass of PizzaIngredientFactory that implements each create method.
② Implement a set of ingredient classes to be used with the factory, like ReggianoCheese, RedPeppers, and ThickCrustDough. These classes can be shared among regions where appropriate.
③ Then we still need to hook all this up by working our new ingredient factories into our old PizzaStore code.
Building the New York ingredient factory
Okay, here’s the implementation for the New York ingredient factory. This factory specializes in Marinara Sauce, Reggiano Cheese, Fresh Clams...
Reworking the pizzas...
We’ve got our factories all fired up and ready to produce quality ingredients; now we just need to rework our Pizzas so they only use factory-produced ingredients. We’ll start with our abstract Pizza class:
Reworking the pizzas, continued...
Now that you’ve got an abstract Pizza to work from, it’s time to create the New York and Chicago style Pizzas—only this time around they will get their ingredients straight from the factory. The franchisees’ days of skimping on ingredients are over!
When we wrote the Factory Method code, we had a NYCheesePizza and a ChicagoCheesePizza class. If you look at the two classes, the only thing that differs is the use of regional ingredients. The pizzas are made just the same (dough + sauce + cheese). The same goes for the other pizzas: Veggie, Clam, and so on. They all follow the same preparation steps; they just have different ingredients.
So, what you’ll see is that we really don’t need two classes for each pizza; the ingredient factory is going to handle the regional differences for us. Here’s the Cheese Pizza:
Let’s check out the ClamPizza as well:
Revisiting our pizza stores
We’re almost there; we just need to make a quick trip to our franchise stores to make sure they are using the correct Pizzas. We also need to give them a reference to their local ingredient factories:
What have we done?
That was quite a series of code changes; what exactly did we do?
We provided a means of creating a family of ingredients for pizzas by introducing a new type of factory called an Abstract Factory.
An Abstract Factory gives us an interface for creating a family of products. By writing code that uses this interface, we decouple our code from the actual factory that creates the products. That allows us to implement a variety of factories that produce products meant for different contexts—such as different regions, different operating systems, or different look and feels.
Because our code is decoupled from the actual products, we can substitute different factories to get different behaviors (like getting marinara instead of plum tomatoes).
An Abstract Factory provides an interface for a family of products. What’s a family? In our case, it’s all the things we need to make a pizza: dough, sauce, cheese, meats, and veggies.
From the abstract factory, we derive one or more concrete factories that produce the same products, but with different implementations.
We then write our code so that it uses the factory to create products. By passing in a variety of factories, we get a variety of implementations of those products. But our client code stays the same.
More pizza for Ethan and Joel...
Ethan and Joel can’t get enough Objectville Pizza! What they don’t know is that now their orders are making use of the new ingredient factories. So now when they order...
Behind the Scenes
The first part of the order process hasn’t changed at all. Let’s follow Ethan’s order again:
From here things change, because we are using an ingredient factory
Behind the Scenes
④ When the createPizza() method is called, that’s when our ingredient factory gets involved:
⑤ Next we need to prepare the pizza. Once the prepare() method is called, the factory is asked to prepare ingredients:
⑥ Finally, we have the prepared pizza in hand and the orderPizza() method bakes, cuts, and boxes the pizza.
Abstract Factory Pattern defined
We’re adding yet another factory pattern to our pattern family, one that lets us create families of products. Let’s check out the official definition for this pattern:
Note
The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
We’ve certainly seen that Abstract Factory allows a client to use an abstract interface to create a set of related products without knowing (or caring) about the concrete products that are actually produced. In this way, the client is decoupled from any of the specifics of the concrete products. Let’s look at the class diagram to see how this all holds together:
That’s a fairly complicated class diagram; let’s look at it all in terms of our PizzaStore:
Is that a Factory Method lurking inside the Abstract Factory?
Good catch! Yes, often the methods of an Abstract Factory are implemented as factory methods. It makes sense, right? The job of an Abstract Factory is to define an interface for creating a set of products. Each method in that interface is responsible for creating a concrete product, and we implement a subclass of the Abstract Factory to supply those implementations. So, factory methods are a natural way to implement your product methods in your abstract factories.
Factory Method and Abstract Factory compared
Tools for your Design Toolbox
In this chapter, we added two more tools to your toolbox: Factory Method and Abstract Factory. Both patterns encapsulate object creation and allow you to decouple your code from concrete types.
A very dependent PizzaStore
Get Head First Design Patterns now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.