什麼時候需要使用單例模式呢?
正如它的名字一樣,你認爲一些東西在整個遊戲中只有一個而你又想可以方便地隨時訪問它,這時你就可以考慮單例模式了。例如,你的遊戲可能需要一個管理音樂播放的腳本,或者一個管理場景切換的腳本,或者一個管理玩家信息的通用腳本,又或者是管理遊戲中各種常用UI的腳本。事實上,這些都是非常常用而且必要的。
實現
代碼大部分都比較容易看懂,下面介紹幾點注意的地方:
- 當我們在其他代碼裏需要訪問某個單例時,只需調用getInstance函數即可,參數是需要訪問的腳本的名字。我們來看一下這個函數。它首先判斷所有單例所在的容器m_Container是否爲空(實際上就是場景中是否存在一個Gameobject,上面捆綁了一個Singleton腳本),如果爲空,它將自動創建一個對象,然後以“Singleton”命名,再捆綁Singleton腳本。m_SingletonMap是負責維護所有單例的映射。當第一次訪問某個單例時,它會自動向m_Container上添加一個該單例類型的Component,並保存在單例映射中,再返回這個單例。因此,我們可以看出,單例的創建完全都是自動的,你完全不需要考慮在哪裏、在什麼時候捆綁腳本,這是多麼令人高興得事情!
- 在Awake函數中,有一句代碼DontDestroyOnLoad (gameObject);,這是非常重要的,這句話意味着,當我們的場景發生變化時,單例模式將不受任何影響。除此之外,我們還要注意到,這句話也必須放到Awake函數,而不能放到Start函數中,這是由兩個函數的執行順序決定的,如果反過來,便可能會造成訪問單例不成功,下面的例子裏會更詳細的介紹;
- 在OnApplicationQuit函數中,我們將銷燬單例模式。
- 最後一點很重要:一定不要在OnDestroy函數中直接訪問單例模式!這樣很有可能會造成單例無法銷燬。這是因爲,當程序退出準備銷燬單例模式時,我們在其他腳本的OnDestroy函數中再次請求訪問它,這樣將重新構造一個新的單例而不會被銷燬(因爲之前已經銷燬過一次了)。如果一定要訪問的話,一定要先調用IsCreatedInstance,判斷該單例是否存在。
例子
注意,爲了方便,我使用了上一篇博文裏使用的Litjson的代碼,並做了少許修改。下面是修改後的LitJsonSample.cs: