我正在更新一些旧代码,原始作者决定将所有命令行参数变量设为全局变量。这显然会增加测试和开发方面的挑战。
我的问题是,如何最好地管理所有类都需要使用的命令行参数(例如跟踪标志/调试标志)。一位同事建议至少将变量包装在命名空间中,但那似乎并不足够。我考虑过单例或静态类,并提供getter方法,但那似乎不太优雅。另一方面,这似乎比需要向每个需要知道是否启用调试和其他一些选项的类传递5个配置选项要好。
我正在更新一些旧代码,原始作者决定将所有命令行参数变量设为全局变量。这显然会增加测试和开发方面的挑战。
我的问题是,如何最好地管理所有类都需要使用的命令行参数(例如跟踪标志/调试标志)。一位同事建议至少将变量包装在命名空间中,但那似乎并不足够。我考虑过单例或静态类,并提供getter方法,但那似乎不太优雅。另一方面,这似乎比需要向每个需要知道是否启用调试和其他一些选项的类传递5个配置选项要好。
const
的事情是需要在开始解析命令行时进行赋值。ProgramArguments
类/结构,其中包含由构造函数通过解析命令行初始化的const成员。然后,您可以像这样:std::unique_ptr<ProgramArguments const> g_program_arguments;
int main(int argc, char* argv[])
{
g_program_arguments.reset(new ProgramArguments(argc, argv));
if(g_program_arguments->verbose)
std::cout << "verbose!" << std::endl;
// ...
return 0;
}
这并不会阻止您将指针更改为指向其他 ProgramArguments 实例。另一种方法是暂时取消 const 属性以进行初始化:
struct ProgramArguments {
ProgramArguments() {}
bool verbose;
};
ProgramArguments const g_program_arguments;
void init_program_arguments(int argc, char* argv[])
{
ProgramArguments& program_arguments = const_cast<ProgramArguments&>(g_program_arguments);
program_arguments.verbose = true;
}
int main(int argc, char* argv[])
{
init_program_arguments(argc, argv);
if(g_program_arguments.verbose)
std::cout << "verbose!" << std::endl;
return 0;
}
这将取决于我们所讨论的全局变量数量。个人认为,对于像调试标志和单例日志管理器之类的东西,拥有一些全局变量是可以接受的。
如果你真的想要完全遵守面向对象编程原则,那么你必须将函数或对象需要的所有内容作为参数传递。永远不要访问全局状态。正如你所提到的,将许多常见参数传递给每个函数很快就会变得乏味,因此可能有一种模式可以帮助你缓解这种情况,那就是上下文对象。