The factory pattern is one of the basic object-oriented design patterns, especially useful in cases where you want to instantiate classes based only on the class name or ID, without specifying the concrete type.
In this post I’ll sketch out a general
Factory template class, which can be used to implement the factory pattern with minimal modification of client code.
Let’s start with an example where we’d like to apply the factory pattern. Say we have a
Projectile interface and some deriving classes which implement different projectile behaviors:
From this there are two main things it would be useful to do:
Grenadeon demand using only the class name (e.g. for scripting purposes).
- Iterate over all
Projectiletypes and get the class name/ID (e.g. for a UI).
We’ll return to (2) after I’ve presented the factory base class. For (1), we can imagine a
Create(const char* _name) which might be implemented as follows:
However it would be nicer to avoid writing a new
else if clause or other boilerplate every time we add a new projectile.
Incidentally, I prefer static
Destroy methods on the interface class over a separate
ProjectileFactory class, if only to reduce namespace pollution. It doesn’t really affect the way this implementation works.
Below is the complete declaration of the
Factory template class:
Factorymaintains a container,
s_registry, which maps class names (or name hashes) to instances of
ClassRefis metadata for the subclasses we want to instantiate (the class name/hash and a ptr to a create function).
ClassRefDefaultprovides a default create function (which just calls
FACTORY_macros are for convenience (since the template declarations are so ugly) and also to allow changes to the implementation without breaking existing code (e.g. changing the type of
- Registration relies on static initialization to populate
s_registry, hence care must be taken to avoid calling any of the methods of
Factoryduring static initialization, because the initialization order is not guaranteed.
Destroytakes a pointer reference so that it can set
_inst_ = nullptr, which just helps to catch dangling ptr bugs.
So, deriving from
Factory we automatically get the required
Destroy methods which can instantiate any registered subclass by name. With this in mind, let’s return to the
Projectile example and ‘factory-fy’ it:
Note that the definitions of
Grenade don’t need to be public - if client code is written only in terms of the
Projectile interface they can be hidden away inside the .cpp, which incurs minimum recompilation when adding new projectile types (but see the notes about static libs below).
The other desirable feature I mentioned earlier (iterating over registered subclasses) can be easily implemented in terms of
Using the code as I’ve presented it, you may run into issues when linking with a static library containing factory subclasses: the registration of the subclasses never happens! The reason is this: because the linker is free to ignore any code in the static lib which it decides has no effect on the executable, the static variables declared by the
FACTORY_REGISTER macros are ignored.
One solution to this problem is to tell the linker not to do this: use
/WHOLEARCHIVE for MSVC or
--whole-archive for GCC. This forces the linker to include everything: it is an all-or-nothing option, though, which can bloat the final executable (though in practice not by much).
We could also exploit the fact that if any code in the same translation unit as the
FACTORY_REGISTER macros is referenced by the executable, the linker must include the whole translation unit. In the example above this is already the case;
s_registry is defined in the same .cpp that our
FACTORY_REGISTER macros appear and because it is externally visible (via the
Projectile interface) the linker has to link everything in the file. If this were not the case, for example if we defined
Grenade in a separate .cpp file, we could use a little hack to achieve the same result:
This is ugly, but is the most portable solution. The
FORCE_LINK_REF macro declares an
int in the translation unit we want to force-link and references it from a function in the executable, defined via the
FORCE_LINK macro. Note that it’s not necessary to actually call the function, simply defining it does the trick.
Another problem arises in that initialization order of
s_registry and the static
ClassRef instances (which add themselves to the registry) are not guaranteed. Depending on the choice of container for
s_registry this may break the whole system - if
ClassRef instances register themselves before
s_registry is initialized it may either crash, or overwrite some or all of the registered pointers when the container is initialized. Bad bad bad.
Fortunately the solution is simple - by amending the code in the
ClassRef ctor we can init the container on demand:
So that’s it - mostly basic stuff, but I didn’t find an implementation exactly like this when looking around. Of course it could be extended to add more features:
- A custom
Destroyfunction per subclass, although this is probably of limited use since you’ll usually have virtual destructors.
- Add a
Factory; this way all subclasses have access to their class metadata which would be a simple way of doing RTTI.