moved documentation
This commit is contained in:
190
typefactory/README.md
Normal file
190
typefactory/README.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user