2011-07-16 104 views
11

我一直在閱讀關於全局變量和它們有多糟糕,但由於這個原因我被困在一個地方。我將非常詳細地說明在這種情況下是否應該使用全局變量。我應該使用全局變量嗎?

我工作的一個遊戲引擎。而我的引擎由很多經理組成。經理做某些任務 - 它們存儲資源,加載它們,更新他們等

我已經做了我所有的經理一個單身,因爲有很多類和函數需要對它們的訪問。我正在考慮取消單身人士,但我不知道我怎麼能拿到這個單身人士,並接觸到這些經理。

這裏是什麼,我想告訴一個例子(在英語,對不起IM壞):

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文件的文件上面。我怎樣才能得到這樣一個沒有全局變量的結果,這將使它易於整合爲一個。單例不是線程安全的,但添加線程不需要很長時間。

我希望我可以解釋這個問題。

由於提前,
卡西姆Gasimzada

+3

沒有什麼神祕的。避免使用全局變量的方法是不擁有它們。如果函數A需要訪問對象B,並且B不是全局的,那麼B已經作爲參數傳遞給A.這就是如果你沒有全局變量的話。將必要的對象作爲函數(或構造函數)參數傳遞。 – jalf

+0

由於我無法評論你的帖子,我會在這裏發表評論。 @jalf我真的明白,全局變量是不好的,另一種可靠的解決方案是將值傳遞給函數或c'tors的參數。但在這種情況下,我遇到了兩個大問題?從那裏我得到這些經理(他們實際上只是包裝,使編碼更容易)? @Dave說要製作'執行'對象(讓它稱爲引擎),它存儲所有這些對象並將引用傳遞給函數或c'tor。但我怎麼做呢?我想讓它更輕鬆,更清潔。 – Gasim

+0

其實從來沒有。我找到了一種方法:)我想要使用單例的唯一原因是因爲我將不得不在每個源文件中只有很少的依賴關係,但現在我找到了一種方法:)感謝各位的幫助!現在重新開始工作。 – Gasim

回答

26

我不會說,你應該從未使用全局變量,但是:

  • 決不使用單身。 Here是原因。它們很可怕,而且比普通的舊環境要糟糕得多。
  • 「經理人」課程是壞的。他們「管理」什麼?他們如何「管理」它? 「經理」類需要被分解成你可以描述的東西。一旦你找出了「管理」一個對象意味着什麼,你可以定義一個或多個具有更好定義職責的對象。
  • 當您使用全局變量,不要讓他們可變的。一個只寫全局是可以接受的(考慮一個記錄器,你寫它,但它的狀態永遠不會影響應用程序),並且只讀全局變量也可以(考慮各種常量永遠不會改變,但你經常需要閱讀)。全局變得有害的地方是當它們有可變狀態時:當你們都讀取它們並寫入它們時。

最後,非常非常簡單的替代方法: 只需傳遞依賴關係作爲參數。如果一個對象需要某些東西來運行,那麼在它的構造函數中傳遞「something」。如果一個函數需要某些東西來操作,那麼將它傳遞給「某些東西」作爲參數。

這可能聽起來了很多工作,但事實並非如此。當你的設計混雜在全局和單例中時,你會得到一個巨大的意大利麪條體系結構,其中一切都依賴於其他任何東西。因爲依賴是沒有明確可見的,你馬虎,而非思考什麼來連接兩個組件的最好方法是,你只要讓他們通過一個或多個全局通信。一旦你必須考慮明確傳遞哪些依賴關係,其中大部分依賴是不必要的,而且你的設計變得更清潔,更易讀和可維護,並且更容易推理。而且你的依賴數量會急劇下降,所以你只需要將一兩個額外的參數傳遞給少量的對象或函數。

+1

但是,std :: cout是一個全局非const對象。我認爲一切都取決於該全球對象的行爲或性質,或程序的上下文。該對象是否有非常小的界面或具有非常緊湊的行爲?好吧,也許全球並不是一個壞主意。 –

3

千萬不要使用全局變量。如果你需要一個類型的對象,那麼你將它傳入,如果需要的話,通過引用。

+3

這是一個過於簡單化的陳述 - 例如,可能會更清楚地擁有一個全局的「記錄器」對象,其中可以調用不同的方法記錄調試信息,而不是將對記錄器對象的引用傳遞給應用程序中的_every_其他對象。 – DaveR

+3

-1是爲了傳達一個好的準則,作爲絕對的必要條件,並給予絕對的推理。我並不是說全局變量是好的,或者在大多數情況下甚至可以接受 - *因爲*我同意全局變量是不好的,我希望這個指南能夠更好地呈現和備份。 – delnan

+3

它可能過於簡單,但建議始終如此。道路上的限速也過於簡單,因爲提供一個完整而準確的賬戶來確定何時以及如何安全地駕駛確切的速度是不切實際的。建議的重點在於提供一條簡單的規則,您可以將其作爲指導原則。它永遠不會考慮*全部*,但根據經驗,「不要使用全局變量」是完全合理的。和@delnan:僅僅因爲你對理論基礎不滿意而下了一個你認同的答案,是非常苛刻的。 :) – jalf

4

如何去除ScriptManager基類,並使用專業化類的靜態方法?它看起來沒有任何國家涉及任何ScriptManagers,除純粹的虛擬功能外沒有真正的遺產。

我無法從你的代碼樣本搞清楚,如果你真的在這裏使用的多態性。如果不是,靜態成員函數對我來說看起來OK。

+1

感謝您的回覆。我實際上已將我的代碼更改爲這樣的內容。並擺脫了所有的單身人士。 – Gasim

+2

@加西姆尼斯!看起來我在這裏有正確的答案! (= – Gabriel

相關問題