我想根据文件扩展名创建程序的新实例。不幸的是,我不能更改界面,因为filename是一个命令行参数。另外,如果要添加新程序,我不喜欢这样做,我必须处理if-else语句。我考虑过用于存储的地图(字符串,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);
}
}
答案 0 :(得分:2)
怎么样?
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派生类,然后在其中进行初始化。