这是一个倒置控制对象存储。它适用于多线程应用程序,它可以在启动时根据复杂的环境设置加载组件,
工作线程可以根据需要检索各个组件。
我需要2个重载的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';
}发布于 2023-01-16 20:44:48
NP和PRS的缩写是什么?我一点线索都没有。特别是对于概念,我会选择清晰的名称来表达这些概念的含义。
Factory是一个非常通用的名称。什么工厂?如果您有一个需要多个工厂类型的代码库,怎么办?我会为这个类选择一个更独特的名称,即使它对任何其他源文件都是不可见的。
它适用于多线程应用程序...。
我在您的代码中没有看到任何互斥或原子操作。请注意,std::unique_ptr与线程安全无关。
我需要2个重载的
registerInstance()函数吗?
不是的。参数包可以绑定到零或多个参数,因此不需要为其设置特例。你只需写:
template <typename T, typename... Ps>
using Generator = std::function<std::unique_ptr<T>(Ps &&...arg)>;
template <typename T>
static void registerInstance(Generator<T> gen)
{
getInstance().factoryMap_[typeid(T)] = gen;
}如果您有一些复杂的场景,其中有两个不同的数据库,该怎么办?也许您有两个从DBOperations派生的不同类,或者只是同一个类,但是您必须将不同的数据库URI传递给构造函数?考虑:
registerInstance<DBOperations>([] {
return std::make_unique<MongoDBOperations>("example.com/db1");
});
registerInstance<DBOperations>([] {
return std::make_unique<CouchDBOperations>("example.com/db2");
});这是一个问题,因为在您的DBOperations中只有一个factoryMap_。同样有问题的是,对registerInstance()的第二个调用将悄悄地覆盖上一个调用。
注册表的问题是它是基于类型进行索引的。因为类型需要在编译时知道,所以有一个运行时映射没有多大意义。您唯一想要的就是能够在定义给定对象之前编写使用它的代码。但是可以在赋值之前声明变量,因此可以:
template <typename T, typename... Ps>
using Generator = std::function<std::unique_ptr<T>(Ps &&...arg)>;
Generator<Handler> handlerGenerator;
Generator<JsonParser> jsonParserGenerator;
Generator<NOSQLOperations> noSQLOperationsGenerator;
Generator<DBOperations> dbOperationsGenerator;
handlerGenerator = [&] { return std::make_unique<Handler>(jsonParserGenerator()); };
jsonParserGenerator = [&] { return std::make_unique<JsonParser>(noSQLOperationsGenerator()); };
noSQLOperationsGenerator = [&] { return std::make_unique<NOSQLOperations>(dbOperationsGenerator()); };
dbOperationsGenerator = [&] { return std::make_unique<DBOperations>(); };
auto handler = handlerGenerator();
std::cout << handler->handle() << '\n';如果要声明包含在多个源文件中的头文件中的实例,可以将它们设置为inline。
注意,现在您可以很容易地声明两个相同类型的不同生成器。
https://codereview.stackexchange.com/questions/282624
复制相似问题