Final version with full refactoring.
This commit is contained in:
@@ -1,119 +1,115 @@
|
|||||||
#ifndef TYPEFACTORY_H
|
#ifndef TYPEFACTORY_H
|
||||||
#define TYPEFACTORY_H
|
#define TYPEFACTORY_H
|
||||||
#include <unordered_map>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility> // std::move
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registry-based factory for creating objects by runtime identifier.
|
* @brief Registry-based factory for creating objects by runtime identifier.
|
||||||
*
|
*
|
||||||
* Allows registering derived types and instantiating them
|
* Allows registering derived types and instantiating them using a ClassId key.
|
||||||
* using a ClassId key.
|
|
||||||
*
|
*
|
||||||
* @param ClassId - unique class identification class. For example string, or integer id.
|
* Notes:
|
||||||
* @param BaseClass - all objects should have one base class. For example vehicle or parameter
|
* - Not thread-safe. Register types during initialization phase only.
|
||||||
* @param Args - constructor arguments
|
* - Re-registering the same id overwrites the previous entry ("last wins").
|
||||||
|
* - ClassId must be hashable (std::hash<ClassId> specialization must exist).
|
||||||
|
*
|
||||||
|
* @tparam ClassId Unique class identifier type (e.g. std::string, int, enum).
|
||||||
|
* @tparam BaseClass Base type for all created objects.
|
||||||
|
* @tparam Args Constructor arguments forwarded to registered derived types (by value).
|
||||||
*
|
*
|
||||||
* Usage example:
|
* Usage example:
|
||||||
* @code
|
* @code
|
||||||
* class Base {
|
* #include <string>
|
||||||
* public:
|
*
|
||||||
|
* struct Base {
|
||||||
|
* virtual ~Base() = default;
|
||||||
* virtual int get() = 0;
|
* virtual int get() = 0;
|
||||||
* }
|
* };
|
||||||
*
|
*
|
||||||
* class Derived1 : public Base {
|
* struct Derived1 : Base {
|
||||||
* public:
|
* explicit Derived1(int start) : m_start(start) {}
|
||||||
* Derived1 (int start) : m_start(start){}
|
* int get() override { return m_start + 1; }
|
||||||
* int get() override {
|
|
||||||
* return m_start + 1;
|
|
||||||
* }
|
|
||||||
* private:
|
|
||||||
* int m_start = 0;
|
* int m_start = 0;
|
||||||
* }
|
* };
|
||||||
*
|
*
|
||||||
* class Derived2 : public Base {
|
* struct Derived2 : Base {
|
||||||
* public:
|
* explicit Derived2(int start) : m_start(start) {}
|
||||||
* Derived2 (int start) : m_start(start){}
|
* int get() override { return m_start + 2; }
|
||||||
* int get() override {
|
|
||||||
* return m_start + 2;
|
|
||||||
* }
|
|
||||||
* private:
|
|
||||||
* int m_start = 0;
|
* int m_start = 0;
|
||||||
* }
|
* };
|
||||||
* .
|
|
||||||
* .
|
|
||||||
* .
|
|
||||||
* TypeFactory <std::string, Base, int> typefactory;
|
|
||||||
* typefactory.registerType<Derived1>("one");
|
|
||||||
* typefactory.registerType<Derived2>("2");
|
|
||||||
*
|
*
|
||||||
* auto d1 = typefactory.creator ("one")(10);
|
* TypeFactory<std::string, Base, int> factory;
|
||||||
* auto d2 = typefactory.creator ("2")(10);
|
* factory.registerType<Derived1>("one");
|
||||||
|
* factory.registerType<Derived2>("two");
|
||||||
*
|
*
|
||||||
* d1->get();
|
* auto a = factory.create("one", 10);
|
||||||
* d2->get();
|
* auto b = factory.creator("two")(10); // advanced API: get creator function
|
||||||
|
*
|
||||||
|
* (void)a->get();
|
||||||
|
* (void)b->get();
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
template <class ClassId, class BaseClass, class... Args>
|
template <class ClassId, class BaseClass, class... Args>
|
||||||
class TypeFactory {
|
class TypeFactory {
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<BaseClass> BaseClass_SP;
|
using BasePtr = std::shared_ptr<BaseClass>;
|
||||||
/**
|
using CreatorFn = BasePtr (*)(Args...);
|
||||||
* @brief typefactoryFunction - typefactory function pointer type. Generally speaking it is pointer to constructor.
|
|
||||||
*/
|
|
||||||
typedef BaseClass_SP (*typefactoryFunction) (Args ...);
|
|
||||||
|
|
||||||
TypeFactory() = default;
|
TypeFactory() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief registerType - template function to register class in factory
|
* @brief Registers a Derived type under the given id.
|
||||||
* @param Derived - registering type
|
|
||||||
* @param id - unique class identification
|
|
||||||
*
|
*
|
||||||
* Usage example:
|
* Requirements (checked at compile-time):
|
||||||
* @code
|
* - Derived must inherit from BaseClass
|
||||||
* typefactory.registerType<Derived1>("one");
|
* - Derived must be constructible from Args...
|
||||||
* typefactory.registerType<Derived2>("2");
|
*
|
||||||
* @endcode
|
* Re-registering the same id overwrites the previous entry ("last wins").
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
void registerType(const ClassId& id) {
|
void registerType(const ClassId& id) {
|
||||||
/// Register Derived type by storing its constructor wrapper
|
|
||||||
static_assert(std::is_base_of_v<BaseClass, Derived>,
|
static_assert(std::is_base_of_v<BaseClass, Derived>,
|
||||||
"Derived must inherit from BaseClass");
|
"Derived must inherit from BaseClass");
|
||||||
static_assert(std::is_constructible_v<Derived, Args...>,
|
static_assert(std::is_constructible_v<Derived, Args...>,
|
||||||
"Derived must be constructible from Args...");
|
"Derived must be constructible from Args...");
|
||||||
classes[id] = &typefactory<Derived>;
|
|
||||||
|
classes.insert_or_assign(id, &instantiate<Derived>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief creator - Returns creator function for id.
|
* @brief Returns creator function for the given id.
|
||||||
* @param id - unique class identification
|
* @throws std::out_of_range when id is not registered.
|
||||||
* @returns creator function.
|
|
||||||
* @throws std::out_of_range when id not found in map
|
|
||||||
*/
|
*/
|
||||||
typefactoryFunction creator (const ClassId& id) const {
|
[[nodiscard]] CreatorFn creator(const ClassId& id) const {
|
||||||
return classes.at(id);
|
return classes.at(id);
|
||||||
}
|
}
|
||||||
BaseClass_SP create(const ClassId& id, Args... args) const {
|
|
||||||
return creator(id)(args...);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
/**
|
/**
|
||||||
* @brief classes - Not thread-safe. Register types during initialization phase only.
|
* @brief Creates an instance for the given id using provided arguments.
|
||||||
|
* @throws std::out_of_range when id is not registered.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<ClassId, typefactoryFunction> classes;
|
[[nodiscard]] BasePtr create(const ClassId& id, Args... args) const {
|
||||||
|
return creator(id)(std::move(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks whether an id is registered.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool contains(const ClassId& id) const {
|
||||||
|
return classes.find(id) != classes.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Protected by design: derived factories may extend/inspect the registry.
|
||||||
|
std::unordered_map<ClassId, CreatorFn> classes;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* @brief typefactory - main functionality, creator registered object
|
|
||||||
* @param Derived - class type
|
|
||||||
* @param args - constructor arguments
|
|
||||||
* @return shared pointer to register Derived class
|
|
||||||
*/
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
static BaseClass_SP typefactory (Args ... args) {
|
static BasePtr instantiate(Args... args) {
|
||||||
return std::make_shared<Derived> (args ...);
|
return std::make_shared<Derived>(std::move(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user