Table of Contents
What is the Abstract Factory Pattern?
In a previous post, I described the Factory Method Pattern and provided a C++ code example. In this post I would like to provide information on another factory pattern, the Abstract Factory Pattern. Let’s jump right in and start with the Abstract Factory Pattern’s formal definition from “Head First Design Patterns”
"The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes"
Ok, so what does this mean? Well let’s break it down a bit shall we? First, the title of Abstract Factory tells me we would have at least one concrete factory object that implements an abstract interface. The second part might not be as clear. What would we consider a “family of related or dependent objects”? This could be a set of objects that are needed to build another object and/or implement a specific behavior(s). If you look at the ingredients of different foods as an example, they could represent the family of objects that make up that food object. More specifically, imagine a Burger as the food object. What objects might make a Burger object complete? This could be a variety of objects like Bun, Pattie, Ketchup, Mustard, Pickles and Onions. There could be any number of variant implementations of these objects. Thus you may consider these abstract objects. The concrete objects could be SesameSeedBun, HeinzKetchup, HeinzMustard, SweetPickles or WhiteOnions. Since part of the definition of the pattern states the concrete classes wouldn’t be exposed via the factory abstract interface, we should expect our abstract objects would be available instead.
What does the Abstract Factory Pattern look like?
Let’s take a look at a generic UML class diagram that illustrates the Abstract Factory Pattern with some classes and their relationships to one another to help paint a picture.
So what is this diagram showing exactly? Well we can expect an interface to our concrete factory as it is part of our Abstract Factory Pattern definition so let’s start there. The AbstractFactory object is our factory abstract interface that provides methods CreateProductA() and CreateProductB() for creating objects that implement abstract objects AbstractProductA and AbstractProductB. There are two concrete factories that implement the factory interface, ConcreteFactory1 and ConcreteFactory2. Each have their own implementations of the CreateProductA() and CreateProductB() methods. The ConcreteFactory1 will create Product1A and Product1B, respectively via these methods whereas ConcreteFactory2 will create Product2A and Product2B, respectively.
The Abstract Factory Pattern through example
Let’s revisit the idea of a Burger object with multiple ingredient objects from earlier in the post. The Burger object would be considered our client where the ingredient objects would be our product objects. Our ingredient objects would have a layer of abstraction that would be exposed to our Burger client through our factory interface. We just need to define our factory objects and interface to complete the pattern. I will re-use the Burger King vs. McDonald theme from my Factory Method Pattern post. So let’s consider a BurgerKingBurgerIngredientsFactory and a McDonaldsBurgerIngredientsFactory that each implement a BurgerIngredientsFactory interface that provides Burger objects a way to create ingredient objects without knowing the details of the specific ingredients. I have created a UML class diagram of all of our objects and their relationships. There are quite a bit of objects here as each implementation of BurgerIngredientFactory has its own set of product objects that implement the abstract product objects. But hopefully it will give you a good visual picture of how our objects are related.
The Abstract Factory Pattern example implementation in C++
Below you can see what the C++ implementation of our factory interface, BurgerIngredientsFactory, looks like. As you can see each Create method is pure virtual and returns an abstraction object versus the concrete ingredient objects.
BurgerIngredientsFactory.h
Next I show the implementations of the factory interface. Each Create method returns a specific type of each ingredient that is associated with the specific factory. For example, the Burger King factory creates a specific SesameSeedBun object to return as Bun in CreateBun(). McDonald’s uses a different type of Bun as it returns SeedlessBun instead.
BurgerKingBurgerIngredientsFactory.cpp
McDonaldsBurgerIngredientsFactory.cpp
I decided to create a Burger object for each type of burger (Burger King vs. McDonalds). These could be considered unnecessary as the implementations are exactly the same but what’s not shown as part of my example is if one burger had an ingredient the other burger didn’t. In that case it would be better to have the separate implementations. For example, if I didn’t have a NoOnions implementation of Onions, then only the McDonaldsBurger would have Onions, specifically WhiteOnions.
BurgerKingBurger.cpp
McDonaldsBurger.cpp
I am just going to show you one ingredient implementation as they are all similar in implementation and there are quite a few. So let’s look at Bun. It’s pretty simple really, just has an empty virtual destructor as well as a Prepare() method declared as pure virtual.
Bun.h
There are two implementations of Bun, SeedlessBun and SesameSeedBun. Each have their own implementation of the Prepare() method.
SeedlessBun.cpp
SesameSeedBun.cpp
Now let’s finally take a look at our test main() function. Basically, each factory is created and passed into its specific Burger object as the BurgerIngredientsFactory interface. Then Prepare() is called on each Burger.
BurgerIngredientsFactoryTest.cpp
The results of the test would look like this…
Preparing Burger King Burger
Preparing Sesame Seed Bun
Preparing Flame Broiled Burger
Preparing Sweet Pickles
Preparing Heinz Ketchup
Preparing Heinz Mustard
Preparing McDonalds Burger
Preparing Seedless Bun
Preparing Grilled Pattie
Preparing Sour Dill Pickles
Preparing White Onions
Preparing McDonalds Ketchup
Preparing McDonalds Mustard
If you would like to try the code out you can find it here.
Benefits of the Abstract Factory Pattern
There are a few benefits to using the Abstract Factory Pattern. For one, it promotes the encapsulation for the creation of objects, meaning the details of object creation are hidden from clients of the factory interface. Another benefit is that it promotes loose coupling as it reduces the dependencies on concrete objects, preferring abstractions instead (Dependency Inversion Principle). Lastly, the pattern favors composition of inheritance with the creation of objects being implemented in methods that are made available in the factory interface.
There can be there can be some disadvantages to the pattern as well. Some may view the implementation of the pattern to be complex. Its important as developers to reduce complexity so make sure the need for the pattern is there. Also, if you have many implementations of the factory interface, it can be expensive if the need for a new product is added.
Conclusion
Well that concludes this post on the Abstract Factory Pattern. I hope you see and appreciate the flexibility and loose coupling the pattern provides. Please feel free to share your thoughts and/or experiences with this pattern in the comments section.
Recommended Resources
Here are some resources I recommend for more information on the Abstract Factory Pattern
Head First Design Patterns: A Brain-Friendly Guide
Design Patterns: Elements of Reusable Object-Oriented Software