Chapter 4. The Factory Pattern: Baking with OO Goodness

Images

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 we don’t want that, do we? Find out how Factory Patterns can help save you from embarrassing dependencies.

Images

When you see “new,” think “concrete.”

Yes, when you use the new operator you are certainly instantiating a concrete class, so that’s definitely an implementation and not an interface. And, you make a good observation: that tying your code to a concrete class can make it more fragile and less flexible.

Images

When we have a whole set of related concrete classes, often we end up writing code like this:

Images

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.

Images

What’s wrong with “new”?

Technically there’s nothing wrong with the new operator. After all, it’s a fundamental part most modern object-oriented languages. 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 many of the 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 your code 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.

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:

Images
Images

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:

Images

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:

Images

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.

Images

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 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...

Images

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:

Images

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,” but the next time that happens you can subtly show you know your stuff, just don’t strut as you educate them on the distinction.

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:

Images
Images

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 abstract 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.

Note

Yes, different areas of the US serve very different styles of pizza—from the deep-dish pizzas of Chicago, to the thin crust of New York, to the crackerlike pizza of California (some would say topped with fruits and nuts).

Images

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...

Images
Images

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?

Images

A framework for the pizza store

There is a way to localize all the pizza-making activities to the PizzaStore class, and to 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:

Images

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.

Images
Images

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.

Images

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!

Images
Images

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:

Images

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:

Images

Let’s see how it works: ordering pizzas with the pizza factory method

Images

So how do they order?

  1. First, Joel and Ethan need an instance of a PizzaStore. Joel needs to instantiate a ChicagoPizzaStore and Ethan needs a NYPizzaStore.

  2. 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).

  3. 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.

  4. 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.

Let’s check out how these pizzas are really made to order...

Images
Images

We’re just missing one thing: Pizzas!

Our PizzaStore isn’t going to be very popular without some pizzas, so let’s implement them:

Images
Images

Now we just need some concrete subclasses... how about defining New York and Chicago st yle cheese pizzas?

Images

You’ve waited long enough. Time for some pizzas!

Images
Images

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:

The Creator classes

Images

The Product classes

Images

View Creators and Products in Parallel

For every concrete Creator, there’s typically a whole set of products that it creates. Chicago pizza creators create different types of Chicago-style pizza, New York pizza creators create different types of New York-style pizza, and so on. In fact, we can view our sets of Creator classes and their corresponding Product classes as parallel hierarchies.

Let’s look at the two parallel class hierarchies and see how they relate:

Images

Inline Design Puzzle

We need another kind of pizza for those crazy Californians (crazy in a good way, of course). Draw another parallel set of classes that you’d need to add a new California region to our PizzaStore.

Images

Okay, now write the five most bizarre things you can think of to put on a pizza. Then, you’ll be ready to go into business making pizza in California!

________________________________

________________________________

________________________________

________________________________

________________________________

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 class 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 “the Factory Method pattern lets subclasses decide which class to instantiate.” Because the Creator class is written without knowledge of the actual products that will be created, we say “decide” not because the pattern allows subclasses themselves to decide, but rather, because the decision actually comes down to which subclass is used to create the product.

Note

You could ask them what “decides” means, but we bet you now understand this better than they do!

Images

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:

Images

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:

Inline Design Principle

Depend upon abstractions. Do not depend upon concrete classes.

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 “lowlevel 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:

Images

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.

Images

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...

Images

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 pizza 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.

Images

Right! You are thinking about the abstraction Pizza. So now, go back and think about the design of the Pizza Store again.

Images

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.

    Note

    If you use new, you’ll be holding a reference to a concrete class. Use a factory to get around that!

  • No class should derive from a concrete class.

    Note

    If you derive from a concrete class, you’re depending on a concrete class. Derive from an abstraction, like an interface or an abstract class.

  • No method should override an implemented method of any of its base classes.

    Note

    If you override an implemented method, then your base class wasn’t really an abstraction to start with. Those methods implemented in the base class are meant to be shared by all your subclasses.

Images

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.

Images

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!

Note

That is, the baking, the cutting, the boxing, and so on...

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:

Images

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? Austin?

For this to work, you are going to have to figure out how to handle families of ingredients.

Images

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:

Images

With that interface, here’s what we’re going to do:

  1. Build a factory for each region. To do this, you’ll create a subclass of PizzaIngredientFactory that implements each create method.

  2. 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.

  3. 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...

Images

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:

Images

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:

Images

Let’s check out the ClamPizza as well:

Images

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:

Images

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.

Images

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 Object ville Pizza! What they don’t know is that now their orders are making use of the new ingredient factories. So now when they order...

Images
Images

The first part of the order process hasn’t changed at all.
Let’s follow Ethan’s order again:

Images

From here things change, because we are using an ingredient factory

Images
Images

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:

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:

Images

That’s a fairly complicated class diagram; let’s look at it all in terms of our PizzaStore:

Images
Images

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

Images
Images

Inline 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.

Images

Inline Design Patterns Crossword

It’s been a long chapter. Grab a slice of Pizza and relax while doing this crossword; all of the solution words are from this chapter.

Images

ACROSS

1. In Factory Method, each franchise is a ________.

4. In Factory Method, who decides which class to instantiate?

6. Role of PizzaStore in Factory Method Pattern.

7. All New York style pizzas use this kind of cheese.

8. In Abstract Factory, each ingredient factory is a _______.

9. When you use new, you are programming to an ___________.

11. createPizza() is a ____________ (two words).

12. Joel likes this kind of pizza.

13. In Factory Method, the PizzaStore and the concrete Pizzas all depend on this abstraction.

14. When a class instantiates an object from a concrete class, it’s ___________ on that object.

15. All factory patterns allow us to __________ object creation.

DOWN

2.We used ___________ in Simple Factory and Abstract Factory, and inheritance in Factory Method.

3. Abstract Factory creates a ___________ of products.

5. Not a REAL factory pattern, but handy nonetheless.

10. Ethan likes this kind of pizza.

Inline Design Puzzle Solution

We need another kind of pizza for those crazy Californians (crazy in a GOOD way, of course). Draw another parallel set of classes that you’d need to add a new California region to our PizzaStore.

Images

Okay, now write the five silliest things you can think of to put on a pizza. Then, you’ll be ready to go into business making pizza in California!

Images

Inline Design Patterns Crossword Solution

It’s been a long chapter. Grab a slice of Pizza and relax while doing this crossword; all of the solution words are from this chapter. Here’s the solution.

Images
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset