Files
cpp-templates/README.md
2026-03-13 13:43:28 -04:00

191 lines
4.2 KiB
Markdown

# 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
- `ClassId` must 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
```cpp
#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:
```cpp
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.
```cpp
factory.registerType<Derived>("id");
```
Compile-time checks ensure that:
- `Derived` inherits from `BaseClass`
- `Derived` is constructible from `Args...`
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.
```cpp
auto fn = factory.creator("id");
```
Throws `std::out_of_range` if the ID is not registered.
### `create`
Creates an object directly by ID.
```cpp
auto obj = factory.create("id", args...);
```
Throws `std::out_of_range` if the ID is not registered.
### `contains`
Checks whether an ID is registered.
```cpp
if (factory.contains("id")) {
// safe to create
}
```
## Design Notes
- `TypeFactory` is 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:
```cpp
// SPDX-License-Identifier: MIT
// Copyright (c) 2025 Dim Himro
```