【发布时间】:2018-01-14 17:48:49
【问题描述】:
我遇到了问题,我的应用程序可能有很多用户输入,这些输入决定了应用程序的运行方式。该应用程序是一个内存数据库系统,例如,用户可以使用诸如“--pagesize 16384”(设置要使用的内存页面大小)、“--alignment 4096”(设置要使用的内存对齐)之类的命令调用该程序或“--measure”(设置标志以测量某些例程)。
目前我将所有用户输入保存在全局变量中,这些变量在头文件中定义为 extern:
//@file common.hh
extern size_t PAGE_SIZE_GLOBAL;
extern size_t ALIGNMENT_GLOBAL;
extern size_t MEMCHUNK_SIZE_GLOBAL;
extern size_t RUNS_GLOBAL;
extern size_t VECTORIZE_SIZE_GLOBAL;
extern bool MEASURE_GLOBAL;
extern bool PRINT_GLOBAL;
extern const char* PATH_GLOBAL;
在主源文件中:
#include "modes.hh"
size_t PAGE_SIZE_GLOBAL;
size_t ALIGNMENT_GLOBAL;
size_t MEMCHUNK_SIZE_GLOBAL;
size_t RUNS_GLOBAL;
size_t VECTORIZE_SIZE_GLOBAL;
bool MEASURE_GLOBAL;
bool PRINT_GLOBAL;
const char* PATH_GLOBAL;
int main(const int argc, const char* argv[]){
...
//Initialize the globals with user input
PAGE_SIZE_GLOBAL = lArgs.pageSize();
ALIGNMENT_GLOBAL = lArgs.alignment();
MEMCHUNK_SIZE_GLOBAL = lArgs.chunkSize();
RUNS_GLOBAL = lArgs.runs();
VECTORIZE_SIZE_GLOBAL = lArgs.vectorized();
MEASURE_GLOBAL = lArgs.measure();
PRINT_GLOBAL = lArgs.print();
std::string tmp = lArgs.path() + storageModel + "/";
PATH_GLOBAL = tmp.c_str();
...
}
然后我在每个文件中包含头文件 common.hh,其中需要一个全局变量(可能在系统中非常深入)。
我已经阅读了十几遍以防止全局变量,所以这显然是不好的风格。在史蒂夫·麦康奈尔 (Steve McConnell) 的“代码完成 2”一书中,关于全局变量的章节也指出要防止全局变量并改用访问例程。在“如何使用访问例程”一节中,他写道
"隐藏类中的数据。使用 static 关键字声明该数据 (...) 以确保仅存在一个数据实例。写 让您查看数据并对其进行更改的例程。”
首先,全局数据不会改变(也许稍后会改变,但至少在不久的将来不会改变)。但我不明白这些访问例程如何更好?我还将在需要数据的每个文件中包含一个类。唯一的区别是全局数据是通过 getter 函数访问的静态成员。
(已编辑)我还考虑过使用全局数据单例类。但是一个包含所有全局数据的对象听起来有点矫枉过正,因为在它的不同目的地只需要对象的几个全局变量。
我的问题:我应该坚持使用全局变量吗?有没有更好的解决方案,我错过了什么?最佳做法是什么?
编辑: 如果我要确定最需要用户输入的几个类,我可以将全局数据更改为成员变量。将用户输入传递给这些类的最佳实践是什么?将数据作为参数通过整个系统传递到最低层听起来是错误的。是否有适合这里的设计模式(考虑类似工厂的东西)?
【问题讨论】:
-
好吧,如果您使用单例类,您实际上不必传递它。方法可以执行类似
Singleton::GetInstance()的操作,这是一个返回Singleton&的静态方法。不过,理想情况下,在 OO 解决方案中,您的数据和方法属于同一个类,因此几乎不会涉及传递。 -
我认为“在不同的目的地只需要对象的几个全局变量”这句话是你真正问题的线索。拥有一组全局变量(或一个仅作为一组全局变量而存在的类)意味着您的其他类最终依赖于全局变量。您认为充满全局变量的单例类并没有好多少的直觉基本上是正确的。这只是重新组织问题。考虑为每个类只提供它需要的最小数据集,即使这会引入一些冗余。更容易理解 + 稍后进行测试。
-
@patatahooligan 我的错,谢谢。即使我能找到一个数据最适合的类,我如何让用户输入这个类?
-
@struthersneil 如何将用户输入(来自 main)传递给实际需要数据的不同类?除了将数据作为参数传递给整个系统之外,还有其他方法吗?我的架构中有不同的层,例如,我不能直接从 main 转到内存管理器。内存管理器需要知道使用的页面大小、对齐方式等。
-
将数据作为参数传递给整个系统并不像听起来那么糟糕。我不确切知道您是如何设置内存管理器的,但假设您的内存管理器是 main 在某个时候实例化的对象,我会将必要的配置传递给构造函数。然后你就有了一个内存管理器,它很容易在不同的配置下单独测试。
标签: c++ global-variables extern