4.2 KiB
TypeFactory
A lightweight registry-based factory for creating objects by runtime identifier.
TypeFactory is a small header-only C++ utility for situations where the exact object type
must be selected dynamically at runtime using an ID.
Typical use cases include:
- protocol command dispatch
- vehicle type identification
- runtime parser or handler selection
- plugin-like object creation
- configuration-based object instantiation
The implementation is intentionally simple and follows the KISS principle.
Features
- header-only implementation
- C++17 compatible
- compile-time validation of registered types
- fast lookup using
std::unordered_map - optional access to creator function for advanced use
- predictable and compact API
- suitable for both commercial and open-source projects
Requirements
- C++17 or newer
ClassIdmust be hashable (std::hash<ClassId>must be available)
Basic Idea
The factory stores a mapping:
- runtime ID -> creator function
A derived type is registered once, then can be created later by its ID.
Example
#include "typefactory.h"
#include <string>
#include <memory>
struct Base {
virtual ~Base() = default;
virtual int get() = 0;
};
struct Derived1 : Base {
explicit Derived1(int start) : m_start(start) {}
int get() override {
return m_start + 1;
}
private:
int m_start = 0;
};
struct Derived2 : Base {
explicit Derived2(int start) : m_start(start) {}
int get() override {
return m_start + 2;
}
private:
int m_start = 0;
};
int main() {
TypeFactory<std::string, Base, int> factory;
factory.registerType<Derived1>("one");
factory.registerType<Derived2>("two");
auto d1 = factory.create("one", 10);
auto d2 = factory.create("two", 10);
return d1->get() + d2->get();
}
Advanced Usage
The factory also provides direct access to the creator function:
auto fn = factory.creator("one");
auto obj = fn(10);
This can be useful when integrating with dispatch tables or higher-level runtime logic.
API Overview
registerType
Registers a derived type for a given runtime ID.
factory.registerType<Derived>("id");
Compile-time checks ensure that:
Derivedinherits fromBaseClassDerivedis constructible fromArgs...
If the same ID is registered again, the previous registration is overwritten. This is intentional: last registration wins.
creator
Returns the creator function associated with the given ID.
auto fn = factory.creator("id");
Throws std::out_of_range if the ID is not registered.
create
Creates an object directly by ID.
auto obj = factory.create("id", args...);
Throws std::out_of_range if the ID is not registered.
contains
Checks whether an ID is registered.
if (factory.contains("id")) {
// safe to create
}
Design Notes
TypeFactoryis not thread-safe during registration.- Types should normally be registered during initialization.
- Lookup and creation are lightweight and predictable.
- The class is designed to be reusable as a low-level infrastructure utility.
- The registry is stored in a protected
std::unordered_map, so derived factories can extend the design if needed.
Why Not Abstract Factory?
This utility is not a classic Abstract Factory pattern.
A classic Abstract Factory typically creates families of related objects.
TypeFactory is closer to a:
- registry-based factory
- type factory
- runtime creator map
It focuses on selecting one concrete type by runtime ID.
Example Use Cases
Vehicle Identification
A controller returns a vehicle ID.
The system uses that ID to create the matching parameter or settings object.
Protocol Command Handling
A command ID is received over the network.
The system selects and creates the correct handler object for that command.
Runtime Format Selection
A parser or converter is selected dynamically depending on file type, message type, or configuration.
License
This project is licensed under the MIT License.
For source files, it is recommended to use SPDX headers such as:
// SPDX-License-Identifier: MIT
// Copyright (c) 2025 Dim Himro