2011-07-16 20 views
11

私はグローバル変数とそれがどれほど悪いかについて読んできましたが、そのために1つの場所に詰まっています。このシナリオでグローバル変数を使用すべきかどうかについて、私は非常に具体的になるでしょう。グローバル変数を使用する必要がありますか?

私はゲームエンジンで作業しています。私のエンジンは多くのマネージャーから構成されています。マネージャは特定のタスクを実行します - リソースを格納し、ロードし、更新します。

非常に多くのクラスと関数がアクセスする必要があるため、すべてのマネージャをシングルトンにしました。私はシングルトンを削除することを考えていたが、私はそれを持つことができないし、これらのマネージャにアクセスすることができないのか分からない。

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()); 
    } 

}; 

エンティティ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. 
} 

アプリケーション

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ファイルに上記のファイルを含めていないです見ての通り。どのようにしてこのような結果を得ることができるのでしょうか?シングルトンはスレッドセーフではありませんが、スレッドの追加には時間がかかりません。

問題を説明できることを願っています。事前に

おかげで、
Gasim Gasimzada

+3

謎はありません。グローバルを避ける方法は、それらを持たないことです。関数AがオブジェクトBにアクセスする必要があり、Bがグローバルでない場合、BはAへの引数として渡されます。これは、グローバルを持たない場合の操作です。必要なオブジェクトを関数(またはコンストラクタ)引数として渡します。 – jalf

+0

あなたの投稿にはコメントできませんので、ここでコメントするつもりです。 @ jalf私は本当にグローバルが悪いと理解しています。代わりの強力な解決策は、値を関数や引数の引数に渡すことです。しかし、私はその場合に2つの大きな問題を抱えていますか?そこから、私はこれらのマネージャーをどこから入手しているのですか(実際にはコーディングを簡単にするラッパーです)。 @Daveは、これらすべてのオブジェクトを格納している「エグゼクティブ」オブジェクト(エンジンと呼ぶことができます)を作成し、関数またはc'torへの参照を渡します。しかし、私はそれをどのようにしていますか?私はそれをより簡単できれいにしたい。 – Gasim

+0

実際には気にしない。私は方法を見つけました:)シングルトンを使用したかった唯一の理由は、各ソースファイルに依存性が非常に少ないためですが、今私は方法を見つけました。今すぐ仕事に戻る。 – Gasim

答えて

26

私は、あなたがすべき決して使用グローバルが、言うことはありません。

  • 決して使用シングルトンを。 Hereがその理由です。彼らは恐ろしいです、そして、彼らは普通の古いグローバルよりはるかに悪いです。
  • "マネージャ"クラスが不良です。彼らは何を "管理"していますか?どのように彼らはそれを "管理"していますか? 「マネージャー」クラスは、あなたが記述できるものに分解される必要があります。オブジェクトを「管理」することが何を意味しているかを理解したら、より明確な責任を持つ1つ以上のオブジェクトを定義できます。
  • グローバルを使用する場合、それらを変更可能にしないでください。書き込み専用のグローバルは受け入れられます(ロガーを考えてみましょうが、書き込みはアプリケーションに影響しません)。また、読み取り専用グローバルも問題ありません(さまざまな定数が変更されることはありませんが、から読む必要があります)。グローバルが有害になるのは、彼らが可変状態をとっているときです:あなたが読んだり書いたりするときです。

最後に、非常に簡単な代替: 引数として依存関係を渡すだけです。オブジェクトが機能するために何かを必要とする場合は、そのコンストラクタにその「何か」を渡します。関数が動作するために何かを必要とする場合は、引数として "何か"を渡します。

これはのようですが、そうではありません。あなたのデザインがグローバルとシングルトンで詰まっていると、すべてが他のすべてに依存する大きな巨大なスパゲッティアーキテクチャが得られます。依存関係が明示的に表示されていないため、2つのコンポーネントを接続する最も良い方法はではなく、と考えています。どの依存関係を明示的に回避するかについて考える必要があると、それらのほとんどは不要であることが判明し、設計ははるかにクリーンで読みやすく保守が容易になり、推論がはるかに容易になります。そしてあなたの依存関係の数は劇的に減少するので、少数のオブジェクトや関数に余分な引数を渡す必要があります。

+1

しかし、std :: coutはグローバルでないconstオブジェクトです。私はすべて、グローバルオブジェクトの動作や性質、プログラムのコンテキストに依存していると思います。そのオブジェクトは非常に小さなインタフェースを持っているのか、非常に詰まった動作をしていますか?確かに、グローバルなことはまったく悪い考えではないでしょう。 –

3

はこれまで、グローバル変数を使用しないでください。型のオブジェクトが必要な場合は、必要に応じて参照で渡します。

+3

これはあまりにも単純なステートメントです。たとえば、さまざまなメソッドが呼び出すことができるグローバルな 'logger'オブジェクトを持つことが明確になるかもしれません。ロガーオブジェクトへの参照をアプリケーション内の他のすべてのオブジェクトに渡すのではなく、デバッグ情報をログに記録します。 – DaveR

+3

-1絶対的な命令として良い指針を説き、絶対にゼロの推論を与えるため。グローバル化が悪いと私は同意するから、そのガイドラインを提示してバックアップしてほしいと思うからだ。 – delnan

+3

あまりにも単純すぎるかもしれませんが、アドバイスは常にです。道路の速度制限はあまりにも単純すぎます。なぜなら、どれくらいの速さがちょうど非現実的であるかを正確に運転することがいつ、どのように安全であるかについての完全で正確な記述を提供するからです。アドバイスのポイントは、ガイドラインとして使用できる簡単なルールを提供することです。これは決して*すべてを考慮に入れることはできませんが、経験則として "グローバル変数を使用しないでください"は完全に妥当です。ANd @ delnan:あなたが同意した答えをdownvotingすることは、あなたがその根拠に満足していないという理由だけで、かなり厳しいです。 :) – jalf

4

ScriptManager基本クラスを削除し、特殊化クラスで静的メソッドを使用することはどうですか? ScriptManagersに関係する州がなく、まったく仮想的な機能以外の本当の遺産がないようです。

ここで実際に多型を使用しているかどうかは、コードサンプルから判断できませんでした。そうでなければ、静的メンバー関数は私には見えます。

+1

お返事ありがとうございます。私は実際に私のコードをこのようなものに変更しました。すべてのシングルトンを取り除いた。 – Gasim

+2

@Gasimニース!私はここに正しい答えがあるように見えます! (= – Gabriel

関連する問題