Robert Larson

  • Home
  • About Me
  • Contact Me
  • Product Recommendations
  • Client Portal

The Abstract Factory Pattern using C++ (Burger King vs. McDonalds Part 2)

The Abstract Factory Pattern using C++ (Burger King vs. McDonalds Part 2)

March 7, 2017 by Robert Larson

Table of Contents

  • What is the Abstract Factory Pattern?
  • What does the Abstract Factory Pattern look like?
  • The Abstract Factory Pattern through example
  • The Abstract Factory Pattern example implementation in C++
  • Benefits of the Abstract Factory Pattern
  • Conclusion
  • Recommended Resources

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

class Bun;
class Pattie;
class Pickle;
class Onions;
class Ketchup;
class Mustard;
class BurgerIngredientsFactory
{
public:
virtual ~BurgerIngredientsFactory() {}
virtual Bun * CreateBun() = 0;
virtual Pattie * CreatePattie() = 0;
virtual Pickle * CreatePickle() = 0;
virtual Onions * CreateOnions() = 0;
virtual Ketchup * CreateKetchup() = 0;
virtual Mustard * CreateMustard() = 0;
};
view raw BurgerIngredientsFactory.h hosted with ❤ by GitHub

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

#include "BurgerKingBurgerIngredientsFactory.h"
#include "FlameBroiledPattie.h"
#include "SesameSeedBun.h"
#include "SweetPickles.h"
#include "NoOnions.h"
#include "HeinzKetchup.h"
#include "HeinzMustard.h"
BurgerKingBurgerIngredientsFactory::BurgerKingBurgerIngredientsFactory() {
}
BurgerKingBurgerIngredientsFactory::~BurgerKingBurgerIngredientsFactory() {
}
Bun * BurgerKingBurgerIngredientsFactory::CreateBun()
{
return new SesameSeedBun();
}
Pattie * BurgerKingBurgerIngredientsFactory::CreatePattie()
{
return new FlameBroiledPattie();
}
Pickle * BurgerKingBurgerIngredientsFactory::CreatePickle()
{
return new SweetPickles();
}
Onions * BurgerKingBurgerIngredientsFactory::CreateOnions()
{
return new NoOnions();
}
Ketchup * BurgerKingBurgerIngredientsFactory::CreateKetchup()
{
return new HeinzKetchup();
}
Mustard * BurgerKingBurgerIngredientsFactory::CreateMustard()
{
return new HeinzMustard();
}
view raw BurgerKingBurgerIngredientsFactory.cpp hosted with ❤ by GitHub

McDonaldsBurgerIngredientsFactory.cpp

#include "McDonaldsBurgerIngredientsFactory.h"
#include "SeedlessBun.h"
#include "GrilledPattie.h"
#include "SourDillPickles.h"
#include "WhiteOnions.h"
#include "McDonaldsKetchup.h"
#include "McDonaldsMustard.h"
McDonaldsBurgerIngredientsFactory::McDonaldsBurgerIngredientsFactory() {
}
McDonaldsBurgerIngredientsFactory::~McDonaldsBurgerIngredientsFactory() {
}
Bun * McDonaldsBurgerIngredientsFactory::CreateBun()
{
return new SeedlessBun();
}
Pattie * McDonaldsBurgerIngredientsFactory::CreatePattie()
{
return new GrilledPattie();
}
Pickle * McDonaldsBurgerIngredientsFactory::CreatePickle()
{
return new SourDillPickles();
}
Onions * McDonaldsBurgerIngredientsFactory::CreateOnions()
{
return new WhiteOnions();
}
Ketchup * McDonaldsBurgerIngredientsFactory::CreateKetchup()
{
return new McDonaldsKetchup();
}
Mustard * McDonaldsBurgerIngredientsFactory::CreateMustard()
{
return new McDonaldsMustard();
}
view raw McDonaldsBurgerIngredientsFactory.cpp hosted with ❤ by GitHub

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

#include "BurgerKingBurger.h"
#include "BurgerIngredientsFactory.h"
#include "Bun.h"
#include "Pattie.h"
#include "Pickle.h"
#include "Onions.h"
#include "Ketchup.h"
#include "Mustard.h"
#include <iostream>
BurgerKingBurger::BurgerKingBurger(BurgerIngredientsFactory * factory)
: m_pBun(factory->CreateBun()),
m_pPattie(factory->CreatePattie()),
m_pPickles(factory->CreatePickle()),
m_pOnions(factory->CreateOnions()),
m_pKetchup(factory->CreateKetchup()),
m_pMustard(factory->CreateMustard()){
}
BurgerKingBurger::~BurgerKingBurger() {
}
void BurgerKingBurger::Prepare()
{
std::cout << "Preparing Burger King Burger\n";
m_pBun->Prepare();
m_pPattie->Prepare();
m_pPickles->Prepare();
m_pOnions->Prepare();
m_pKetchup->Prepare();
m_pMustard->Prepare();
}
view raw BurgerKingBurger.cpp hosted with ❤ by GitHub

McDonaldsBurger.cpp

McDonaldsBurger::McDonaldsBurger(BurgerIngredientsFactory * factory)
: m_pBun(factory->CreateBun()),
m_pPattie(factory->CreatePattie()),
m_pPickles(factory->CreatePickle()),
m_pOnions(factory->CreateOnions()),
m_pKetchup(factory->CreateKetchup()),
m_pMustard(factory->CreateMustard()){
}
McDonaldsBurger::~McDonaldsBurger() {
}
void McDonaldsBurger::Prepare()
{
std::cout << "Preparing McDonalds Burger\n";
m_pBun->Prepare();
m_pPattie->Prepare();
m_pPickles->Prepare();
m_pOnions->Prepare();
m_pKetchup->Prepare();
m_pMustard->Prepare();
}
view raw McDonaldsBurger.cpp hosted with ❤ by GitHub

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

#ifndef BUN_H_
#define BUN_H_
class Bun
{
public:
virtual ~Bun() {}
virtual void Prepare() = 0;
};
view raw Bun.h hosted with ❤ by GitHub

There are two implementations of Bun, SeedlessBun and SesameSeedBun. Each have their own implementation of the Prepare() method.

SeedlessBun.cpp

#include "SeedlessBun.h"
#include <iostream>
SeedlessBun::SeedlessBun() {
}
SeedlessBun::~SeedlessBun() {
}
void SeedlessBun::Prepare()
{
std::cout << "Preparing Seedless Bun\n";
}
view raw SeedlessBun.cpp hosted with ❤ by GitHub

SesameSeedBun.cpp

#include "SesameSeedBun.h"
#include <iostream>
SesameSeedBun::SesameSeedBun() {
}
SesameSeedBun::~SesameSeedBun() {
}
void SesameSeedBun::Prepare()
{
std::cout << "Preparing Sesame Seed Bun\n";
}
view raw SesameSeedBun.cpp hosted with ❤ by GitHub

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

int main()
{
BurgerIngredientsFactory * factory = new BurgerKingBurgerIngredientsFactory();
Burger * burger = new BurgerKingBurger(factory);
burger->Prepare();
delete burger;
delete factory;
std::cout << "\n";
factory = new McDonaldsBurgerIngredientsFactory();
burger = new McDonaldsBurger(factory);
burger->Prepare();
delete burger;
delete factory;
}
view raw BurgerIngredientsFactoryTest.cpp hosted with ❤ by GitHub

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

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

Posted in: c++, Design Patterns Tagged: c++, designpatterns
← The Factory Method Pattern using C++ (Burger King vs. McDonalds)
Singleton Pattern using C++ →
  • Home
  • About Me
  • Contact Me
  • Product Recommendations
  • Client Portal

Recent Posts

  • March Madness 2019 – Weighted Random Bracket Generator
  • Gifts Ideas for Software Developers 2018-2019
  • March Madness 2018 – Second Chance Weighted Random Bracket Generator
  • March Madness 2018 – Weighted Random Bracket Generator
  • Builder Pattern using C++ (NFL Scheduler Example)

Archives

  • March 2019
  • November 2018
  • March 2018
  • August 2017
  • June 2017
  • May 2017
  • April 2017
  • March 2017
  • February 2017
  • January 2017

Follow me on Twitter

My Tweets

Copyright © 2025 Robert Larson.

Grace WordPress Theme by SiteChurch

%d