我应该使用全局变量吗?
我一直在阅读有关全局变量以及它们有多糟糕的内容,但因此我被困在一个地方。我将非常具体地说明在这种情况下是否应该使用全局变量。
我正在开发游戏引擎。我的引擎由很多经理组成。管理器执行某些任务 - 他们存储资源、加载资源、更新资源等。
我已将所有管理器设置为单例,因为有很多类和函数需要访问它们。我正在考虑删除单例,但我不知道如何才能拥有它并访问这些管理器。
这是我想要讲述的示例(抱歉,我英语不好):
Singleton.h
template<class T> class Singleton {
private:
Singleton( const Singleton& );
const Singleton& operator=( const Singleton& );
protected:
Singleton() { instance = static_cast<T*>(this); }
virtual ~Singleton() {}
protected:
static T * instance;
public:
static T &Instance() {
return *instance;
}
};
ScriptManager.h
class ScriptManager : public Singleton<ScriptManager> {
public:
virtual void runLine(const String &line)=0;
virtual void runFile(const String &file)=0;
};
PythonScriptManager.cpp
class PythonScriptManager : public ScriptManager {
public:
PythonScriptManager() { Py_Initialize(); }
~PythonScriptManager() { Py_Finalize(); }
void runFile(const String &file) {
FILE * fp = fopen(file.c_str(), "r");
PyRun_SimpleFile(fp, file.c_str());
fclose(fp);
fp=0;
}
void runLine(const String &line) {
PyRun_SimpleString(line.c_str());
}
};
Entity ScriptComponent
#include <CoreIncludes.h>
#include <ScriptManager.h>
#include <ScriptComponent.h>
void update() {
ScriptManager::Instance().runFile("test_script.script");
//i know its not a good idea to open the stream on every frame but thats not the main concern right now.
}
Application
int main(int argc, const char * argv) {
Application * app = new Application(argc, argv);
ScriptManager * script_manager = new PythonScriptManager;
//all other managers
return app->run();
}
正如您所见,我什至没有将上面的文件包含在我的 ScriptComponent.cpp 文件中为我赢得了一些编译时间。如果没有全局变量,我怎样才能得到这样的结果,这将使它很容易像这样集成。单例不是线程安全的,但是添加线程不会花费很长时间。
我希望我能解释这个问题。
预先感谢,
卡西姆·加西姆扎达
I have been reading about global variables and how bad they are but I am stuck in one place due to that. I am going to be very specific about if I should use global variables in this scenario.
I am working on a game engine. And my engine consists of lots of managers. Managers do certain tasks - they store resources, load them, update them etc.
I have made all my managers a singleton because so many classes and functions needs access to them. I was thinking of removing the singleton but I don't know how i can not have it and get access to these managers.
Here is an example of what I am trying to tell (im bad at english, sorry):
Singleton.h
template<class T> class Singleton {
private:
Singleton( const Singleton& );
const Singleton& operator=( const Singleton& );
protected:
Singleton() { instance = static_cast<T*>(this); }
virtual ~Singleton() {}
protected:
static T * instance;
public:
static T &Instance() {
return *instance;
}
};
ScriptManager.h
class ScriptManager : public Singleton<ScriptManager> {
public:
virtual void runLine(const String &line)=0;
virtual void runFile(const String &file)=0;
};
PythonScriptManager.cpp
class PythonScriptManager : public ScriptManager {
public:
PythonScriptManager() { Py_Initialize(); }
~PythonScriptManager() { Py_Finalize(); }
void runFile(const String &file) {
FILE * fp = fopen(file.c_str(), "r");
PyRun_SimpleFile(fp, file.c_str());
fclose(fp);
fp=0;
}
void runLine(const String &line) {
PyRun_SimpleString(line.c_str());
}
};
Entity ScriptComponent
#include <CoreIncludes.h>
#include <ScriptManager.h>
#include <ScriptComponent.h>
void update() {
ScriptManager::Instance().runFile("test_script.script");
//i know its not a good idea to open the stream on every frame but thats not the main concern right now.
}
Application
int main(int argc, const char * argv) {
Application * app = new Application(argc, argv);
ScriptManager * script_manager = new PythonScriptManager;
//all other managers
return app->run();
}
As you see I am not even including the files above in my ScriptComponent.cpp file which wins me some compilation time. How can I get that kind of a result without globals which will make it easy to integrate as this one. The singleton is not thread safe but adding threads won't take a long time.
I hope I could explain the problem.
Thanks in advance,
Gasim Gasimzada
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不会说你永远不应该使用全局变量,但是:
最后,非常非常简单的替代方案:
只需将依赖项作为参数传递即可。如果一个对象需要某些东西才能运行,请在其构造函数中传递该“东西”。如果函数需要某些东西才能运行,请将“某些东西”作为参数传递给它。
这听起来可能需要大量工作,但事实并非如此。当你的设计中充斥着全局变量和单例变量时,你会得到一个巨大的意大利面条式架构,其中一切都依赖于其他一切。因为依赖关系不是明确可见的,所以你会变得草率,而不是思考连接两个组件的最佳方式是什么,你只是让它们通过一个或多个全局变量进行通信。一旦您必须考虑显式传递哪些依赖项,大多数依赖项都会被证明是不必要的,并且您的设计会变得更加清晰、更具可读性和可维护性,并且更容易推理。并且您的依赖项数量将急剧下降,因此您实际上只需要向少量对象或函数传递一个或两个额外的参数。
I won't say you should never use globals, but:
And finally, the very very simple alternative:
Just pass dependencies as arguments. If an object needs something in order to function, pass it that "something" in its constructor. If a function needs something in order to operate, pass it that "something" as an argument.
This might sound like a lot of work, but it isn't. When your design is cluttered with globals and singletons, you get a big huge spaghetti architecture where everything depends on everything else. Because the dependencies are not explicitly visible, you get sloppy, and rather than thinking about what the best way to connect two components is, you just make them communicate through one or more globals. Once you have to think about which dependencies to explicitly pass around, most of them turn out to be unnecessary, and your design becomes much cleaner, more readable and maintainable, and much much easier to reason about. And your number of dependencies will drop dramatically, so that you only actually need to pass an extra argument or two to a small number of objects or functions.
删除 ScriptManager 基类并在专业化类中使用静态方法怎么样?看起来任何 ScriptManager 都没有涉及任何状态,除了纯虚函数之外也没有真正的继承。
我无法从你的代码示例中弄清楚你是否真的在这里使用了多态性。如果没有,静态成员函数对我来说看起来不错。
How about removing the
ScriptManager
base class and use static methods in the specialization classes? It looks like there is no state involved with anyScriptManagers
, and no real heritage other than the purely virtual functions.I could not figure out from your code samples if you actually use polymorphism here. If not, static member functions look OK to me.
永远不要使用全局变量。如果您需要某种类型的对象,则可以在必要时通过引用传递它。
Do not ever use global variables. If you need an object of a type, then you pass it in, by reference if necessary.