Unity 單例模式


明天十一放假,今天不知什么原因看到一篇unity單例模式的介紹,瞬間來了戾氣。

(一)最簡單的單利

public class WebRequestUtility : MonoBehaviour
{
    public static WebRequestUtility Instance;

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

這是最簡單有效,最實用最沒問題的單利模式。如果說存在什么問題,那就是在別的腳本awake中引用,若果其他腳本中的awake比上述awke先執行,則會報空引用。此問題通過設置腳本執行順序課解決。題外話,一般初始化啟動盡量用start,除非是非常確定要先運行用awake,不要為了先執行而用awake;

(二)構造函數法

public class WebRequestUtility : MonoBehaviour
{
    public static WebRequestUtility Instance;

    WebRequestUtility()
    {
        Instance = this;
    }

}

構造函數中初始化instance最先執行,會在awake之前(官方為找到直接說明,但是鑒於腳本先初始化而后運行,會比awake先執行,事實也是這樣,如果有人發現有問題再議,來互懟)。但在2017unity版本中遇到過bug(緊遇到一次),即剛開始運行時,構造函數多次運行,原因未找到。

(三)DontDestroyOnLoad情況下的單例模式

有時候單例不能隨着場景的加載而消失,需要一直存在,所以需要不能銷毀,但是加載時場景中就會存在兩個單例(這個說法本身有問題,即本來已經有單例,但是在場景加載時awake又重新運行的情況)

public class WebRequestUtility : MonoBehaviour
{
    public bool bDontDestroyOnLoad = false;

    public static WebRequestUtility Instance;

    private void InitializeInstance()
    {
        if (Instance != null & Instance == this)
            return;

        if(bDontDestroyOnLoad)
        {
            if(Instance==null)
            {
                Instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
            }
        }
        else
        {
            Instance = this;
        }
    }

    private void Awake()
    {
        InitializeInstance();
    }
}

上述代碼參考自unity的NetworkManager組件的源代碼。邏輯很簡單,只允許有一個單例,引用時,除了保證單例已經初始化(不為空),還要保證單例==this。否則就是單例被重新賦值了,即在別的地方又重新初始化,既然使用單例模式這是不允許的。

(四)靜態屬性或者靜態方法法

public class WebRequestUtility : MonoBehaviour
{
    private static WebRequestUtility instance;
    
    public static WebRequestUtility Instance
    {
        get
        {
            if(instance==null)
            {
                instance = new WebRequestUtility();
            }

            return instance;
        }
    }
}

這種也是一種比較好的方法,但是沒有(一)(二)簡潔,一般用於獲取單例時需要再初始化等問題時,對於大部分單例模式(一)(二)已經夠用。

(四)單例模式亂象(真正互懟開始)

本想再這部分直接開始懟的,但是寫到這人戾氣已經沒了,還是好好學習的好啊,學習讓我心平氣和。繼續說某度出的unity單例的問題。

1)單例變”多例“

從他代碼角度確實時要單例,但是經過幾行代碼后變成多例,然后又經過幾行代碼,然后可從多個事例中return一個”單例“(???),本想直接上鏈接懟的,想想還是算了。可以看看此文https://blog.csdn.net/qq_15267341/article/details/54232854,多簡介,多明了。

2)使用鎖(lock)

使用鎖沒有任何問題,但是unity中不推薦使用。再.net中單例模式必須加鎖,因為再多線程中統一使用單例會出現沖突等等問題,比如死鎖,或者邏輯未理清出問題。但是unity是單線程操作,通過協程來實現“異步“操作,所以不存在此問題。當然也存在開線程的問題,但是開線程或者異步操作只針對純數據層面的操作,因為在非主線程中是無法進行組件操作的(通俗講就是操作unity自定義的東西)。所以在unity中異步或者開線程時,基本可以避免在其他線程中調用主線程中的單例情況(針對游戲層面,vr ar來說)。在極少數非要進行相關處理的(一般是在回調時出現),也可以通過在update中實時檢測來解決。當然了,如果你的單例不涉及到unity相關組件操作,那也就不用繼承mono,就可以用純C#的語法來處理了。

 

 

最后竟然一點戾氣都沒有了。。。。。。。。。。。。。。。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM