This is an inversion-of-control object store. It is meant to be for a multithreaded application where it can load components at start-up based on complex environmental setup,
Worker threads can retrieve individual components on demand.
Do I need 2 overloaded functions of registerInstance()?
#include <iostream>
#include <vector>
#include <memory>
#include <ranges>
#include <memory>
#include <algorithm>
#include <unordered_map>
#include <iterator>
#include <any>
#include <typeindex>
#include <functional>
template <typename... Args>
concept NP = sizeof...(Args) == 1;
template <typename... Args>
concept PRS = sizeof...(Args) > 1;
class Factory
{
public:
template <PRS T, typename... Ps>
using Generator2 = std::function<std::unique_ptr<T>(Ps &&...arg)>;
template <NP T>
using Generator = std::function<std::unique_ptr<T>()>;
template <NP T>
void registerInstance(Generator<T> gen)
{
factoryMap_[typeid(T)] = gen;
}
template <PRS T>
void registerInstance(Generator2<T> gen)
{
factoryMap_[typeid(T)] = gen;
}
template <NP T>
std::unique_ptr<T> resolve()
{
auto it = factoryMap_.find(typeid(T));
try
{
return it == factoryMap_.end() ? nullptr : std::any_cast<Generator<T>>(it->second)();
}
catch (const std::bad_any_cast &o)
{
// logit
throw o;
}
}
static Factory &getInstance()
{
static Factory instance;
return instance;
}
private:
std::unordered_map<std::type_index, std::any> factoryMap_;
};
class DBOperations
{
public:
virtual ~DBOperations() = default;
virtual std::string handle() const
{
return "DB Opeation";
}
};
class NOSQLOperations
{
public:
virtual ~NOSQLOperations() = default;
NOSQLOperations(std::unique_ptr<DBOperations> &&obj) : compD_{std::move(obj)} {}
std::string handle() const
{
return compD_->handle() + "-NO SQL";
}
private:
std::unique_ptr<DBOperations> compD_;
};
class JsonParser
{
public:
JsonParser(std::unique_ptr<NOSQLOperations> &&obj) : compC_{std::move(obj)} {}
virtual ~JsonParser() = default;
std::string handle() const
{
return compC_->handle() + "-Json Parser";
}
private:
std::unique_ptr<NOSQLOperations> compC_;
};
class Handler
{
public:
virtual ~Handler() = default;
Handler(std::unique_ptr<JsonParser> &&obj) : compB_{std::move(obj)} {}
std::string handle() const
{
return compB_->handle() + "-Handler";
}
private:
std::unique_ptr<JsonParser> compB_;
};
void registerComponents()
{
auto &ioc = Factory::getInstance();
ioc.registerInstance<Handler>([&] { return std::make_unique<Handler>(ioc.resolve<JsonParser>()); });
ioc.registerInstance<JsonParser>([&] { return std::make_unique<JsonParser>(ioc.resolve<NOSQLOperations>()); });
ioc.registerInstance<NOSQLOperations>([&] { return std::make_unique<NOSQLOperations>(ioc.resolve<DBOperations>()); });
ioc.registerInstance<DBOperations>([&] { return std::make_unique<DBOperations>(); });
}
int main()
{
registerComponents(); // can be called at startup
auto &ioc = Factory::getInstance();
auto i = ioc.resolve<Handler>();
std::cout << i->handle() << '\n';
}