Unity 單例模式

單例模式是設(shè)計模式中很常用的一種模式齐佳,它的目的是讓一個類在程序運(yùn)行期間有且只有一個實(shí)例抓艳。關(guān)于 Unity 中如何實(shí)現(xiàn)單例模式其實(shí)有很多文章鬓椭,但是我找不到一篇能夠完整講述整個單例模式實(shí)現(xiàn)流程的文章盛嘿,大部分都是直接貼代碼昨寞,這對于我這種不喜歡知其然瞻惋,卻不知其所以然的人來說是遠(yuǎn)遠(yuǎn)不夠的,所以我翻閱了國外一些資料援岩,在這里寫下這篇文章歼狼,旨在通過完整的流程講述如何在 Unity 中實(shí)現(xiàn)單例模式,以及實(shí)現(xiàn)該模式時需要注意的一些事項享怀,希望能夠幫助初學(xué)者羽峰。另外,如有任何錯誤請盡管指出。

項目源碼倉庫:https://github.com/darylgo/UnitySingleton

1 單例模式的應(yīng)用場景

在使用 Unity 開發(fā)游戲的時候梅屉,經(jīng)常會需要各種 Manager 類用于管理一些全局的變量和方法值纱,例如最常見的 GameManager 用于記錄各種需要在整個游戲過程中持久化的數(shù)據(jù)。本文以 GameManager 為例坯汤,假設(shè)我們有以下幾個需求:

  1. 整個游戲過程中必須有且只有一個 GameManager
  2. 在 GameManager 里會記錄一個叫 Value 的整型變量
  3. 切換游戲場景的時候 GameManager 不能被銷毀
  4. 有兩個游戲場景分別叫 FirstScene 和 SecondScene
  5. 每一個場景中都會有一個按鈕计雌,點(diǎn)擊后會跳轉(zhuǎn)到另一場景,并且對 GameManager.Value 進(jìn)行 +1 操作
  6. 每一個場景中都會顯示當(dāng)前 GameManager.Value 的值

下面我們就來一步步實(shí)現(xiàn)單例模式下的 GameManager玫霎。

2 實(shí)現(xiàn)單例模式的 GameManager

首先凿滤,我們會定義一個類叫 GameManager,它繼承了 MonoBehaviour庶近,具體代碼如下所示:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    public int Value { get; set; } = 0;

    private void Awake()
    {
        Instance = this;
    }
}
  1. 靜態(tài)的 GameManager 屬性 Instance 保證了它可以通過類訪問翁脆,而不是通過實(shí)例訪問。
  2. Instance 屬性私有的 set 保證了它只允許在 GameManager 內(nèi)部賦值鼻种,外部只能讀取反番。
  3. 繼承 MonoBehaviour 類的實(shí)例都是又 Unity 游戲引擎創(chuàng)建的,不能通過構(gòu)造函數(shù)創(chuàng)建叉钥,所以我們在 Awake() 方法里對 Instance 進(jìn)行賦值罢缸,保證了我們能夠在第一時間初始化。

創(chuàng)建完 GameManager 類之后投队,我們需要在游戲場景中創(chuàng)建一個也叫做 GameManager 的 GameObject枫疆,并且把 GameManager 類作為 Component 添加到 GameObject 上:

接下來,我們要處理實(shí)現(xiàn)單例模式時遇到的第一個問題敷鸦,就是 Unity 在切換游戲場景的時候息楔,默認(rèn)會消除上一個游戲場景里所有的 GameObject 對象,所以我們的 GameManager 對象也不可避免的會被銷毀扒披,這是我們不希望看到的值依,所以我們使用 DontDestroyOnLoad() 方法讓 GameManager 在切換游戲場景的時候不會被銷毀:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    public int Value { get; set; } = 0;

    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

在處理完 GameManager 被銷毀的情況之后,我們要再處理另一個問題碟案,就是我們的 GameManager 是在第一個場景里創(chuàng)建的愿险,當(dāng)我們從第二個游戲場景切換回第一個游戲場景的時候,Unity 并不是恢復(fù)第一個游戲場景价说,而是會重新創(chuàng)建出一個新游戲場景辆亏,這就會導(dǎo)致一個新的 GameManager 對象被創(chuàng)建,這就不能保證 GameManager 對象的唯一性熔任,如下所示:

要解決上面的問題褒链,我們需要在 GameManager 類的 Awake() 方法里增加一些邏輯判斷,當(dāng)檢查到已經(jīng)有一個 GameManager 對象存在的時候疑苔,就把當(dāng)前的 GameManager 對象銷毀甫匹,如下所示:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    public int Value { get; set; } = 0;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

3 通用單例模式

單例模式在開發(fā)過程中十分常見,所以我們經(jīng)常會使用泛型寫一個單例模式的基類,這樣我們就可以通過繼承該基類輕松實(shí)現(xiàn)單例模式兵迅,代碼如下所示:

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    public static T Instance { get; private set; }

    protected void Awake()
    {
        if (Instance == null)
        {
            Instance = (T) this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

我們使用 Singleton 基類實(shí)現(xiàn)我們的 GameManager抢韭,代碼如下所示:

public class GameManager : Singleton<GameManager>
{
    public int Value { get; set; } = 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恍箭,隨后出現(xiàn)的幾起案子刻恭,更是在濱河造成了極大的恐慌,老刑警劉巖扯夭,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鳍贾,死亡現(xiàn)場離奇詭異,居然都是意外死亡交洗,警方通過查閱死者的電腦和手機(jī)骑科,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來构拳,“玉大人咆爽,你說我怎么就攤上這事≈蒙” “怎么了斗埂?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凫海。 經(jīng)常有香客問我呛凶,道長,這世上最難降的妖魔是什么盐碱? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任把兔,我火速辦了婚禮,結(jié)果婚禮上瓮顽,老公的妹妹穿的比我還像新娘。我一直安慰自己围橡,他們只是感情好暖混,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翁授,像睡著了一般拣播。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上收擦,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天贮配,我揣著相機(jī)與錄音,去河邊找鬼塞赂。 笑死泪勒,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播圆存,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼叼旋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沦辙?” 一聲冷哼從身側(cè)響起夫植,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎油讯,沒想到半個月后详民,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陌兑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年阐斜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诀紊。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡谒出,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邻奠,到底是詐尸還是另有隱情笤喳,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布碌宴,位于F島的核電站杀狡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贰镣。R本人自食惡果不足惜呜象,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碑隆。 院中可真熱鬧恭陡,春花似錦、人聲如沸上煤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劫狠。三九已至拴疤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間独泞,已是汗流浹背呐矾。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懦砂,地道東北人蜒犯。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓组橄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親愧薛。 傳聞我的和親對象是個殘疾皇子晨炕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355