Unity中通用的单例模板

前言:单例(Singleton)是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
无论什么语言都会有用到单例的地方,最基础的单例示例如下:

public class Test
{
    static protected Test _instance;
    static protected bool IsCreate = false;

    public static Test Instance
    {
        get
        {
            if (IsCreate == false)
            {
                CreateInstance();
            }

            return _instance;
        }
    }

    public static void CreateInstance()
    {
        if (IsCreate == true)
            return;

        IsCreate = true;
        _instance = new Test();
    }

    public static void ReleaseInstance()
    {
        _instance = default(Test);
        IsCreate = false;
    }
}

上面这部分代码就实现了单例,可以直接通过Test.Instance访问类型,当然这么编写后外部还能通过new Test()再次创建Test类的对象,如果不想外部再次创建,那么需要把Test类的构造访问权限改成私有或者受保护的,例如:

    protected Test()
    {
        
    }

    private Test()
    {
        
    }

然而如果多个类需要使用单例,我们不会在每个类里面都写一遍单例部分的代码,因此就有了编写通用的单例模板类的原因,那么需要有单例的类,只要继承单例模板类,就拥有了单例类的特性,同样的也会有缺陷,就比如构造函数没办法改成私有或者受保护的,但不妨碍他的使用便利性。

同样的Unity中如果需要挂载在Unity的GameObject上面,那么就需要继承Unity中独有的MonoBehaviour,并且如果改对象切换场景不删除的话还需要调用DontDestroyOnLoad

因此在Unity中单例模板,可以分为三种
1、不继承MonoBehaviour的单例
2、继承MonoBehaviour的单例
3、继承MonoBehaviour并且DontDestroyOnLoad的单例

下面就直接放上Unity中直接可用的三种单例模板

namespace TenderRain.Core
{
    public class Singleton<T> where T : new()
    {
        protected static T _instance;
        protected static bool IsCreate = false;

        public static T Instance
        {
            get
            {
                if (IsCreate == false)
                {
                    CreateInstance();
                }

                return _instance;
            }
        }

        public static void CreateInstance()
        {
            if (IsCreate == true)
                return;

            IsCreate = true;
            _instance = new T();
        }

        public static void ReleaseInstance()
        {
            _instance = default(T);
            IsCreate = false;
        }
    }

    /// <summary>
    /// 这样可以避免使用new来构造单例对象。通过DontDestroyOnLoad,gameobject来构造对象,
    /// 单例带来可能带来内存泄露问题和线程安全问题
    /// </summary>
    public class Singleton_DontDestroy<T> : UnityEngine.MonoBehaviour where T : UnityEngine.MonoBehaviour
    {
        private static T _instance;

        private static object _lock = new object();

        public static T Instance
        {
            get
            {
                if (applicationIsQuitting)
                {
                    UnityEngine.Debug.LogWarning($"[Singleton_DontDestroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} already destroyed on application quit. Won't create again - returning null.");

                    return null;
                }

                if (_instance == null)
                {
                    lock (_lock)
                    {
                        if (_instance == null)
                        {
                            var objects = UnityEngine.Resources.FindObjectsOfTypeAll(typeof(T));

                            if (objects.Length > 1)
                            {
                                _instance = objects[0] as T;

                                UnityEngine.Debug.LogWarning($"[Singleton_DontDestroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} Something went really wrong there should never be more than 1 singleton! Reopening the scene might fix it.");

                                return _instance;
                            }

                            if (_instance == null)
                            {
                                _instance = new UnityEngine.GameObject().AddComponent<T>();
                                _instance.name = "[Singleton_DontDestroy] " + typeof(T).ToString();
                                DontDestroyOnLoad(_instance.transform.root.gameObject);
                                UnityEngine.Debug.Log($"[Singleton_DontDestroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} was created with DontDestroyOnLoad.");
                            }
                            else
                            {
                                _instance.name = "[Singleton_DontDestroy] " + typeof(T).ToString();
                                DontDestroyOnLoad(_instance.transform.root.gameObject);
                                UnityEngine.Debug.Log($"[Singleton_DontDestroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} already existed with DontDestroyOnLoad.");
                            }
                        }
                    }
                }
                return _instance;
            }
        }

        protected static bool applicationIsQuitting = false;

        public static bool IsApplicationQuitting
        {
            get { return applicationIsQuitting; }
        }

        protected virtual void Awake()
        {
            if (_instance == null)
            {
                _instance = this as T;
                DontDestroyOnLoad(_instance.transform.root.gameObject);
            }
            else if (_instance != this)
                Destroy(gameObject);
        }

        public virtual T CastInstanceType()
        {
            if (_instance == null)
                _instance = this as T;
            else if (_instance != this)
                _instance = _instance as T;
            return _instance;
        }

        public void SetInstance(T instance, bool isNotNullSet = false)
        {
            _instance = _instance == null || isNotNullSet ? instance : _instance;
        }

        protected virtual void OnCreated()
        {

        }

        protected virtual void OnDestory()
        {
            _instance = null;
            applicationIsQuitting = true;
        }
        protected virtual void OnApplicationQuit()
        {
            _instance = null;
            applicationIsQuitting = true;
        }

        public static T Create()
        {
            return Instance;
        }
    };
    public class Singleton_Destory<T> : UnityEngine.MonoBehaviour where T : UnityEngine.MonoBehaviour
    {
        private static T _instance;

        private static object _lock = new object();

        public static T Instance
        {
            get
            {
                if (applicationIsQuitting)
                {
                    UnityEngine.Debug.LogWarning($"[Singleton_Destroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} already destroyed on application quit. Won't create again - returning null.");

                    return null;
                }

                if (_instance == null)
                {
                    lock (_lock)
                    {
                        if (_instance == null)
                        {
                            var objects = UnityEngine.Resources.FindObjectsOfTypeAll(typeof(T));

                            if (objects.Length > 1)
                            {
                                _instance = objects[0] as T;

                                UnityEngine.Debug.LogWarning($"[Singleton_Destroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} Something went really wrong there should never be more than 1 singleton! Reopening the scene might fix it.");

                                return _instance;
                            }

                            if (_instance == null)
                            {
                                _instance = new UnityEngine.GameObject().AddComponent<T>();
                                _instance.name = "[Singleton_Destroy] " + typeof(T).ToString();

                                UnityEngine.Debug.Log($"[Singleton_DontDestroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} was created with DestroyOnLoad.");
                            }
                            else
                            {
                                _instance.name = "[Singleton_Destroy] " + typeof(T).ToString();

                                UnityEngine.Debug.Log($"[Singleton_Destroy] Instance Type = {typeof(T)} Name = {_instance.gameObject.name} already existed with DestroyOnLoad.");
                            }
                        }
                    }
                }
                return _instance;
            }
        }

        protected static bool applicationIsQuitting = false;

        public static bool IsApplicationQuitting
        {
            get { return applicationIsQuitting; }
        }

        protected virtual void Awake()
        {
            if (_instance == null)
                _instance = this as T;
            else if (_instance != this)
                Destroy(gameObject);
        }

        public virtual T CastInstanceType()
        {
            if (_instance == null)
                _instance = this as T;
            else if (_instance != this)
                _instance = _instance as T;
            return _instance;
        }

        public void SetInstance(T instance, bool isNotNullSet = false)
        {
            _instance = _instance == null || isNotNullSet ? instance : _instance;
        }

        protected virtual void OnDestory()
        {
            _instance = null;
            applicationIsQuitting = true;
        }
        protected virtual void OnApplicationQuit()
        {
            _instance = null;
            applicationIsQuitting = true;
        }

        public static T Create()
        {
            return Instance;
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TenderRain。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值