Factories are an extremely useful design pattern in programming. If you do not know what the factory pattern is, it is simply a way for code to generate instances of objects by specifying a unique identifier. In this example, I have chosen to go with a text adventure visit to an eatery with the name of FoodFactory. The player can type in the name of an item they want to order, and the code will generate an instance of that object, call some class member functions, and destroy it. The player does not need to define what a taco is in detail, the kitchen should be able to cook him up a delicious taco by simply typing the word “Taco” into the command window. If only it were that simple in real life…

You may be curious as to why I have decided to write a tutorial on the factory pattern. After all, there are countless examples on factory patterns available via a simple Google search. Well, the secret sauce here is that each object that can be created by the factory registers itself with the factory, rather than the factory registering each item. This is a small, but significant deviation to how the factory pattern is traditionally implemented. That is not to say this is a new technique (see the comment from Jess below), however, this is a less talked about pattern that I believe deserves some more attention.

The Example Project

In order to demonstrate the Auto Registering Factory pattern, I have put together a project on my GitHub page with all of the code that is referenced in this article. The intention is so that you can jump into the details of my implementation to understand it better and possibly even copy some of the code into your own projects.

If you run the example code, you will be prompted with a text adventure-like sceneario of you entering an eatery named FoodFactory. As the player, you can request a list of what FoodFactory can create, request a specific item to be created, or exit the application. I have decided to use an eatery in this example to make it a little more interesting than creating instances of Foo and Bar.

In the code, the class FoodFactory is a singleton factory class, and it creates instances of objects that derive from the base class FoodObject. There are three classes that inherit from FoodObject which all can be created via the singleton instance of FoodFactory. Those classes are Taco, Burrito, and Hamburger. Each FoodObject implementation exposes functions for getting the number of calories in the food, as well as a boolean flag to determine if it is a commonly ordered item at FoodFactory.

The factory and FoodObject classes exist in a project that produces a DLL that is consumed by the user interface executable. The UI is a console application that prompts the player to enter in commands.

You can view or clone the repository on my GitHub page here.

Why break tradition?

Later in this post we will get into the pros and cons of this pattern, but for now I will focus on demonstrating the usefulness of this auto registration factory pattern, and in order to do that, I must quickly talk about how the traditional pattern works. As mentioned before, traditionally your factory class needs to know about each class that it can create. In C++ this means that every time you add a new class that you want the factory to be able to create, you need to do a few things. First, you create your header and cpp file for the class. Then you have to edit the cpp file for the factory class to include the header of the new class you created, and then add a line to the constructor or initialization method to register the new type with the factory.

This works fine if the number of objects you want to potentially create is relatively small. However, when you add more classes, your factory class gets full of boilerplate code that may start driving you mad. Here is an example of what the factory class may end up looking like:

#include "FoodFactory.h"
#include "Burrito.h"
#include "Taco.h"
#include "Taquito.h"
#include "Sopes.h"
#include "Chilaquiles.h"
#include "Torta.h"
#include "Hamburger.h"
// ... The list could go on. I must stop for brevity. Also, I am writing this on
// an empty stomach and this could be classified as a form of self harm.

FoodFactory::FoodFactory()
{
    Register("Burrito", []() { return std::make_shared<Burrito>(); });
    Register("Taco", []() { return std::make_shared<Taco>(); });
    Register("Taquito", []() { return std::make_shared<Taquito>(); });
    Register("Sopes", []() { return std::make_shared<Sopes>(); });
    Register("Chilaquiles", []() { return std::make_shared<Chilaquiles>(); });
    Register("Torta", []() { return std::make_shared<Torta>(); });
    Register("Hamburger", []() { return std::make_shared<Hamburger>(); });
    // ... etc
}

// ... all the other code has been omitted for brevity

It may not seem all that annoying at first, but it is something that will gnaw at you as your project grows. Imagine what this code would look like when the factory needs to be able to create hundreds of FoodObject types and you will get the idea of why I was looking for an alternative.

The Auto Registering Factory Pattern

The Setup

In order to address the issue presented here, we must flip the problem on its head. As shown in the example above, the factory knows about each and every class it can instantiate and is responsible for registering each type. With the auto registering factory pattern, the classes register themselves with the factory. It’s a simple concept, but surprisingly difficult to implement in C++.

The problem here is that there is no clear place to put the code that will register the class with the factory and trigger execution of that code automatically. The trick is to find a place within the header and/or cpp file that will automatically call our registration code for us.

When I originally wrote this article, I relied on static methods on the FoodObject classes as well as some macros. As some users on Reddit have pointed out, there are cleaner ways of achieving this. Credit goes to xurxoham and JeffMcClintock for pointing me in the right direction here. Instead of macros and static methods, we are going to rely on constructors of global objects to do the work for us.

We should first take a look at the virtual class FoodObject and a concrete implementation of it. Here is the code for FoodObject.h and Taco.h

#pragma once
#include "FoodFactoryRegistration.h"

class FoodObject
{
public:
	virtual int getCalories() const = 0;
	virtual bool isCommonlyOrdered() const = 0;
};
#pragma once
#include "FoodObject.h"

class Taco : public FoodObject
{
public:
	virtual int getCalories() const override { return 200; }
	virtual bool isCommonlyOrdered() const override { return true; }
};

namespace FoodFactoryRegistrations {
	FoodFactoryRegistration<Taco> _Taco("Taco");
}

Here you can see that FoodObject has two functions; getCalories and isCommonlyOrdered. Taco.h implements the FoodObject interface and defines itself as having 200 calories and is a commonly ordered item.

The Factory

Before we talk about how to implement auto registration, we should understand what the factory class looks like.

#pragma once
#include <string>
#include <unordered_map>

#ifdef BUILD_DLL
#define DLL_INTERFACE __declspec(dllexport)
#else
#define DLL_INTERFACE __declspec(dllimport)
#endif

class FoodObject;

typedef FoodObject*(*foodInstanceGenerator)();

class FoodFactory
{
public:
	DLL_INTERFACE static FoodFactory& get();

	DLL_INTERFACE const char** getMenu(int & count);
	DLL_INTERFACE FoodObject* orderFood(const char* typeName);
	DLL_INTERFACE bool registerGenerator(
							const char* typeName,
							const foodInstanceGenerator& funcCreate);

private:
	FoodFactory();
	FoodFactory(const FoodFactory&);
	~FoodFactory();

	std::unordered_map<std::string, foodInstanceGenerator> m_generators;
};

We begin the code by including string and unordered_map. We use string because we are going to store our unique identifiers for each class as a std::string object. We also use unordered_map because we need to store a map that contains our string key paired with a function pointer to a method that can create an instance of the object.

After the includes, there is a macro definithion for DLL_INTERFACE which is necessary to export certain functions so that the calling code can easily use this DLL. This is typically stored elsewhere like a precompiled header, but I have included it here for clarity as it is the only file where the macro is used.

We then forward declare FoodObject. If we were to include “FoodObject.h” instead, we would end up with a cyclical reference problem. FoodObject already references “FoodFactory.h” so if we let FoodFactory include “FoodObject.h” we would get some nasty compiler errors. Since all we need to know about FoodObject is that it exists and we can return a pointer to it, a forward declaration is all we need.

Next, we use a typedef declaration to make an alias (foodInstanceGenerator) for a function pointer that creates an instance the base class FoodObject on the heap and returns a pointer to it. You do not have to create this alias, but it does make the code much more readable.

After all of that is the actual definition of the FoodFactory class. I have broken down the functions in the sections below.

Exploring get()

The first function in the class is a simple getter for our singleton object. This method also lazy-loads the singleton instance until it is called for the first time. We have to do that in order to ensure that the factory exists when objects are being registered. The “why” will be more apparent later on in the article as I explain how we make the components register themselves. One thing to note is that this singleton pattern is guaranteed to be thread safe in C++11 or greater.

FoodFactory & FoodFactory::get()
{
	static FoodFactory instance;
	return instance;
}

Exploring getMenu()

This function returns an array of strings that contains all of the unique identifiers for each generator in the factory. Since it is a pointer to a list of char pointers, you do have to take care when calling this to delete each string value first, and then delete the array after that to avoid memory leaks. You will see this in the implementation of the main function below.

const char** FoodFactory::getMenu(int & count)
{
	count = m_generators.size();
	const char** arrayHead = new const char* [count];

	int i = 0;
	for (auto g : m_generators)
	{
		size_t bufferSize = g.first.length() + 1;
		char* generatorIdBuffer = new char[bufferSize];
		strncpy_s(generatorIdBuffer, bufferSize, g.first.c_str(), g.first.length());
		arrayHead[i++] = generatorIdBuffer;
	}

	return arrayHead;
}

Exploring orderFood()

The next function, orderFood, takes in the name of the item you want to instantiate, creates an instance of FoodObject from the generator, and returns a pointer to the object on the heap. If no generator matches the type passed into the function, a null pointer is returned and the error case can be handled by the calling code.

FoodObject* FoodFactory::orderFood(const char* typeName)
{
	auto it = m_generators.find(typeName);
	if (it != m_generators.end())
	{
		return it->second();
	}

	return nullptr;
}

Exploring registerGenerator()

The final function in the class is what registers a new generator. It takes the unique identifier, and the reference of a function that creates an instance of the class associated with that unique identifier. It will attempt to find if a generator with that name already exists in the generator map. If one does not exist, it inserts one with the information provided and returns true. If a generator with the same ID is found, then nothing is added to the generator list and false is returned.

bool FoodFactory::registerGenerator(
		const char* typeName,
		const foodInstanceGenerator & funcCreate)
{
	return m_generators.insert(std::make_pair(typeName, funcCreate)).second;
}

Exploring the private parts

Under the private keyword, we have the class’ constructors/destructor and our map object that contains each generator. The constructor and destructor are listed as private because we want to hide them since this is intended to be used as a singleton object only. The destructor also does not need to be exposed for any reason so we hide that here as well. The m_generators map object is the only member variable necessary to make this factory work.

AutoRegister template class

Having set the ground work of what FoodFactory and FoodObject look like, we now need to tie the two together. As mentioned before, we are going to be using global variable constructors to register our FoodObject types, but we didn’t define the object type of the global variable. I have created a class called FoodFactoryRegistration that only contains a constructor. This constructor takes in a string identifier and in the definition of the constructor we call the register method on the factory.

#pragma once
#include "FoodFactory.h"

namespace FoodFactoryRegistrations {

	template <typename T>
	class FoodFactoryRegistration
	{
	public:
		FoodFactoryRegistration(const char* id)
		{
			FoodFactory::get().registerGenerator(
				id,
				[]() { return static_cast<FoodObject*>(new T()); }
			);
		}
	};

}

Making the Taco Register Itself

The final step to all of this is to create a global variable of type FoodFactoryRegistration in the FoodObject class type that we want to self-register. I have opted to put these global variables under the namespace FoodFactoryRegistrations. This is optional, but it helps keep your namespace clean. Within the namespace we just need to create an instance of FoodFactoryRegistration and call the constructor with the unique identifier we want to associate the type with. I have included the entire contents of Taco.h and Taco.cpp below with all of our changes.

#pragma once
#include "FoodObject.h"

class Taco : public FoodObject
{
public:
	virtual int getCalories() const override { return 200; }
	virtual bool isCommonlyOrdered() const override { return true; }
};

namespace FoodFactoryRegistrations {
	FoodFactoryRegistration<Taco> _Taco("Taco");
}
#include "Taco.h"

Why the empty cpp file?

Surely you noticed that our taco.cpp file is empty, right? Technically it isn’t empty because we have one line importing Taco.h. But why? Well, that is because the compiler does not compile header files at all. C++ compilers only compile translation units, and by default, the only files that are treated as translation units are .c and .cpp files. Because of this, we do need a cpp file that includes the header to make sure it is included in the build. Chances are, the objects you want to construct are not this simple and you will need a cpp file to define your methods anyway, so this could have been easily looked over.

Using the Factory

Using the factory is fairly straightforward. You will need to include FoodFactory.h and FoodObject.h in order to use the objects. Then, whenever you are ready to use the factory, you simply call FoodFactory::get() to get the singleton instance and you can then call the getMenu or the orderFood functions. I have included the majority of the main.cpp file below so you can see how I implemented the calls to the DLL. The code block is collapsed by default, so you will want to click the link below to expand it.

#include <iostream>
#include <string>
#include "FoodFactory.h"
#include "FoodObject.h"

// The definitions for printPreamble, printDialogueNoInput, printDialogueExit,
//  and printDialogueCannotMake have been ommitted for brevity.

int main()
{
	printPreamble();

	std::string inputCommand;
	bool willGetSick = false;

	// Here is an infinite loop so that we can continuously prompt the user until they exit
	while (42)
	{
		// Prompt the user for a command
		std::cout << "You: ";
		std::getline(std::cin, inputCommand);

		// Handle the case where no command was given
		if (inputCommand == "")
		{
			printDialogueNoInput();
		}
		// Handle the exit command so the user can terminate the infinite loop
		else if (inputCommand == "exit")
		{
			printDialogueExit(willGetSick);
			// This break command will terminate the loop
			break;
		}
		// Handle the request to see the menu
		else if (inputCommand == "?")
		{
			// Call getMenu and store the length of the array and pointer to it in numMenuItems and menuItems respecively
			int numMenuItems = 0;
			const char** menuItems = FoodFactory::get().getMenu(numMenuItems);

			// numMenuItems now stores the count of items that exist in the array
			std::cout << "Dan: We have " << numMenuItems << " things:\n";

			// Iterate through each item in the array and print them out
			for (int i = 0; i < numMenuItems; i++)
			{
				std::cout << "         " << menuItems[i] << '\n';
			}

			// Remember to delete the items in the array and the array itself because it is all allocated on the heap
			for (int i = 0; i < numMenuItems; i++)
			{
				delete[] menuItems[i];
			}
			delete[] menuItems;
		}
		else
		{
			// Attempt to order food with the name that the user entered
			FoodObject* food = FoodFactory::get().orderFood(inputCommand.c_str());

			// If we are given an actual pointer to an instance of a FoodObject
			if (food != nullptr)
			{
				// Print out the command and some information about this instance of FoodObject, notice that the result of
				//  getCalories is different depending on the type of food that was created.
				std::cout << "Dan: Order up! Here is your \"" << inputCommand << "\"!\n";
				std::cout << "* You ate it and now have " << food->getCalories() << " more calories of energy. Good for you! *\n";

				// Here is another example of getting unique information from our constructed instance of FoodObject.
				if (!food->isCommonlyOrdered())
				{
					std::cout << "Dan (under his breath): Nobody ever orders those things here... I hope he doesn't get sick.\n";
					willGetSick = true;
				}

				// Remember to delete the FoodObject since it was allocated on the heap
				delete food;
			}
			else
			{
				printDialogueCannotMake(inputCommand);
			}
		}
	}

	return 0;
}

Should You Use This Pattern?

This design pattern is quite powerful, but we all know the old adage from Uncle Ben. How do you know if this pattern is right for your project?

When to use it

You should use this pattern if:

  • you have many classes that need to be created by the factory.
  • you do not need to have objects be registered in a particular order.

When to avoid it

You should avoid this pattern if:

  • you need to see what the factory needs to create by just looking at the code.
  • singletons are not frowned upon in your codebase.
  • you care about objects getting created and potentially never used.

Other things to note

Since the FoodFactoryRegistration class calls the default constructor, your class must not hide the default constructor. You can modify FoodFactoryRegistration to accept parameters if you really need parameters to be passed to your objects, or you can make your global objects a boolean value and manually create the generator callback lambda in the class file and pass the parameters you want to use.

Also, to extrapolate a bit on the last bullet point above, you will have to note that these objects get created each and every time your application starts up. If you have an application that needs to quickly start up, process some work, and then shut down without touching those variables, you are wasting clock cycles initializing your factory that you may not end up needing.

How I am Using This Pattern

I have used this pattern in the Derydoca game engine for registering game component classes. Since I am often adding new game component classes to the project, it is easy for me to forget to add it to the factory class. I have spent plenty of time trying to figure out what is wrong with my game component class when I simply forgot to add it to the factory.

Example Repo on GitHub

You can see all of the code discussed here and more on my git hub repository page. You can use it to study this pattern in detail and bring it into your own project.

Let me know if you have or plan to use this in a project of your own in the comments below.

Additional Remarks

This article has been rewritten with the feedback received on my Reddit thread and in the comments below. Special thanks go out to everyone who helped refine this implementation of the auto registering factory pattern.

Reddit Thread

Contributors

2 Comments

  • Jess says:

    Hi,
    You can use unordered_map like to avoid a double lookup:

    bool FoodFactory::registerGenerator
    (
    const std::string & typeName,
    const foodInstanceGenerator & funcCreate
    )
    {
    return m_generators.insert(std::make_pair(typeName, funcCreate)).second;
    }

    Fun fact: I implemented a factory very similar to yours almost 20 years ago, Iā€™m still using it today !

  • Thank you for sharing that! I just implemented your code and appreciate it’s efficiency and succinctness! Also, it’s nice to hear that this technique has been used in some long living codebases. šŸ™‚

Leave a Reply