根据参数创建派生类的新实例
Posted
技术标签:
【中文标题】根据参数创建派生类的新实例【英文标题】:Create new instance of a derived class depending on a parameter 【发布时间】:2019-11-06 11:53:27 【问题描述】:我想根据文件扩展名创建新的程序实例。不幸的是,我无法更改界面,因为文件名是命令行参数。另外,如果我想添加新程序,我不喜欢这样,我必须处理 if-else 语句。我考虑过用于存储 (string, type_index) 的地图,但显然这种方法不适用于模板。此外,我尝试通过传递 constexpr 字符串比较函数来处理 std::enable_if ,但这显然也不起作用。我想我可以通过创建一堆函数并根据字符串比较选择一个函数来以某种方式扩展后一种方法。基本上,我想要的是实现可扩展性并符合 SOLID 原则。
std::shared_ptr<Program> Program::fromFile(const Path& file)
auto extension = file.extension();
if(extension == "cpp")
return std::make_shared<CppProgram>(file);
else if(extension == "py")
return std::make_shared<PythonProgram>(file);
else if(extension == "java")
return std::make_shared<JavaProgram>(file);
else if(extension == "go")
return std::make_shared<GoProgram>(file);
else
throw std::runtime_error("unknown file extension " + extension);
【问题讨论】:
您已经回答了您的问题。这正是你的做法。任何其他变体都将基本相同,但更加模糊。 使用工厂注册(创作者的)。要扩展只需在工厂注册一个新的创建者。工厂只是询问每个创建者“你能从这个文件中创建吗”它是否可以返回结果,如果它不能尝试下一个。 【参考方案1】:这个怎么样?
struct Maker
virtual shared_ptr<Program> make(const Path& file) = 0;
;
map<string, unique_ptr<Maker>> g_makers;
std::shared_ptr<Program> Program::fromFile(const Path& file)
auto extension = file.extension();
auto it = g_makers.find(extension);
if(it == g_makers.end())
throw std::runtime_error("unknown file extension " + extension);
return it->second->make(file);
// probably in a separate file:
struct CppMaker : Maker
shared_ptr<Program> make(const Path& file) override
return make_shared<CppProgram>(file);
;
__attribute__((constructor))
static void initCppMaker()
g_makers["cpp"].reset(new CppMaker());
现在您需要做的就是决定何时以及如何将各种 Maker 实现注册到 g_makers
。您可以使用特定于编译器的语法(如 GCC 的 __attribute__((constructor))
)或其他初始化技术来执行此操作。您可以在单独的翻译单元中定义每个 Maker 派生类并在那里进行初始化。
【讨论】:
你能举一个使用这种技术注册的例子吗?以上是关于根据参数创建派生类的新实例的主要内容,如果未能解决你的问题,请参考以下文章