Complementary video tutorial on this topic found at the bottom of this article.
What is the Factory Design Pattern?
In short, the Factory Design Pattern gives you 3 main benefits:
- It gives you a way to create an object from one of several possible classes
- It provides a common interface to use the newly created object
- It lets you hide (isolate) the creation logic from the client
Sound confusing? It’s really not, the factory pattern is very common and one of the easiest design patterns to understand. But first, let’s look at a more confusing definition:
Original definition by the “Gang of Four”
The Factory Design Pattern defines an interface for creating an object, but you let the subclasses decide which class to instantiate. Factory method lets a class defer instantiation to subclasses
“Design Patterns – Elements of Reusable Object-Oriented Software”
Ok, so what the heck does that mean?
Let’s think of it this way.
I have a problem. My problem is that I love beer. Ok, well that’s not really my problem – my actual problem is that I love beer so much, that I have a hard time trying to choose which beer I want to drink at any given time.
I mean there’s just so many to choose from – IPA, Porter, Stout, Pilsner, Dark Lager, American Sour – the list goes on…
So I’ve decided, I’m not going to make this decision for myself anymore. Instead, I’m going to let my assistant choose which beer I want. (Ok, I don’t actually have my own personal assistant, but just go along with me here on this example).
So I don’t care which beer my assistant chooses, I just want a beer chosen for me.
This is essentially the Factory Design Pattern here. I, the client, need a beer. I don’t necessarily need to know which beer I get, nor do I need to care about how the beer is made. The only thing I really need to know is that if I order a beer, I’m expecting some type of beer to be returned to me.
My assistant, the beer Factory, will select one of several different classes of beer, all of which implement a beer interface.
To get a better representation of this concept, let’s see what a simple UML diagram for this might look like for this beer scenario:
Some things may be named a little bit different and in a different order than last time, but it’s still the same exact concept. We still have 4 main parts here:
- The Client (me) – I order a random beer from the BeerFactory
- The BeerFactory (the assistant) – contains the necessary logic on how to choose a random beer. Perhaps it has logic to choose some type of Ale on Monday, and an IPA on Tuesday. Or perhaps it has logic to select a certain beer based on the hour. Or maybe this beer is for a meal and the type is chosen based on the entree. Whatever that logic is, the client does not need to care. The client just expects a type of beer.
- The Beer – an abstract class that comes with 5 default steps on brewing a beer. An abstract class cannot be instantiated, but it can be subclassed. Each Beer Subclass may override this default behavior, but no matter what these 5 steps will be included in every beer type created.
- Beer Subclasses – The actual beer that gets created. Each beer will have its own special ingredients and may override the 5 brewing steps for their own brew (creation) process.
Hey by the way, if you want to learn more about design patterns, I highly recommend you use my affiliate link to get the book Head First Design Patterns. It’s by far the best book to learn about design patterns!
>>> Click here to Order on Amazon >>> Head First Design Patterns: A Brain-Friendly Guide
How to implement the Factory Design Pattern
Let’s dive into some code now. We will create a very basic Java program around our Random Beer example above to demonstrate the simple Factory Design Pattern.
(And if you don’t know Java, don’t worry – design patterns aren’t tied to a specific language. It’s the pattern that’s important to understand and recognizing when and how to use the pattern)
Coding without the Factory Pattern
First, let’s see what life would be like if we didn’t use a Factory Pattern. We’ll start with a Main class to drive our program, and create 2 subclasses that extend a Beer abstract class. Our program will be designed to brew a Stout beer on Mondays, and an IPA beer on any other day of the week.
/* Main.java */
import java.util.Calendar;
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
Beer myBeer = null;
if (day == calendar.MONDAY) {
myBeer = new StoutBeer();
} else {
myBeer = new IPABeer();
}
myBeer.brew();
}
}
Code language: JavaScript (javascript)
/* Beer.java */
public abstract class Beer {
public abstract void malting();
public abstract void steeping();
public abstract void boiling();
public abstract void fermentation();
public abstract void bottling();
public void brew() {
malting();
steeping();
boiling();
fermentation();
bottling();
}
}
Code language: PHP (php)
/* IPABeer.java */
public class IPABeer extends Beer {
public void malting() { System.out.println("Malting with rye grains"); }
public void steeping() { System.out.println("Steep grains through boiling water at 170 degrees"); }
public void boiling() { System.out.println("Boil wort for 60 minutes"); }
public void fermentation() { System.out.println("Let sit for 14"); }
public void bottling() { System.out.println("Your IPA beer has been bottled!"); }
}
Code language: PHP (php)
/* StoutBeer.java */
public class StoutBeer extends Beer {
public void malting() { System.out.println("Malting with oat grains"); }
public void steeping() { System.out.println("Steep grains through boiling water at 160 degrees"); }
public void boiling() { System.out.println("Boil wort for 75 minutes"); }
public void fermentation() { System.out.println("Let sit for 20 days"); }
public void bottling() { System.out.println("Your stout beer has been bottled!"); }
}
Code language: PHP (php)
(Note: the above “convention” of writing those functions one line is ONLY meant to save space on this blog. Please follow your style guide, which most likely (hopefully) prevents you from using such convention)
(Also Note: I don’t actually know how to brew beer, and I did VERY little, although some, research to the steps or variations of steps per types of beer, if applicable. I’m sorry if I offended any brewers here with this most likely inaccurate information)
Alright, so what’s wrong with the above code? Well, it violates one core principle to software engineering best practices, the Open/Close Principle.
The Open/ Closed Principle (OCP)
The OCP states that software entities should be open for extension, but closed for modification. In the example code above, what happens when we add a new beer type to the equation, say brewing a PorterBeer on Tuesdays. Well we’d need to open up the Main.java file and modify the if-else statements.
Or what if the creation logic needs to completion change or get reworked, again we’d be violating the Open/ Closed Principle and not following clean code standards.
DRY Principle
You could also make the case that we’d end up violating the DRY principle at some point, which stands for Don’t Repeat Yourself. Imagine as this program grows, we may eventually need this functionality or logic to be used in multiple places for multiple different occasions.
With this current approach, we’d end up having to duplicate this creation logic to many different places. What a maintenance nightmare!
So let’s see how we can fix this code with the use of the Factory Design Pattern.
Creating the BeerFactory
First, let’s start by creating the BeerFactory. We’re going to strip out any functionality from our Main class that relates to the creation of a Beer.
/* BeerFactory.java */
import java.util.Calendar;
public class BeerFactory {
public Beer getBeer() {
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
if (day == calendar.MONDAY) {
return new StoutBeer();
} else {
return new IPABeer();
}
}
}
Code language: PHP (php)
Now, all we need to do is to update our Main class to use the BeerFactory.
/* Main.java */
public class Main {
public static void main(String[] args) {
BeerFactory beerFactory = new BeerFactory();
Beer myBeer = beerFactory.getBeer();
myBeer.brew()<code>;</code>
}
}
Code language: PHP (php)
Wow! Look at how much cleaner our Main class is now! We removed all the unnecessary logic behind what goes into choosing which beer to brew and isolated it to its own Factory.
When to use the Factory Design Pattern?
The Factory Design Pattern allows you to separate the object construction code from the code that actually uses the object. This makes it easier to extend the object construction code, independently from the rest of the code!
Use the Factory Pattern when:
- you don’t know ahead of time what class object you might need
- you don’t want the client to know every type of possible subclass
- you want to centralize class selection
- you want to encapsulate object creation
- all the possible classes inherit from a common super class
If you want to learn more about design patterns, I highly recommend you use my affiliate link to get the book Head First Design Patterns. It’s by far the best book to learn about design patterns!
>>> Head First Design Patterns: A Brain-Friendly Guide