浅谈单例模式在游戏开发中的应用

前言

如果在外部想在不同的时间结点、不同的位置访问某类中的成员且想要保持访问时,成员地址唯一。

那么可以考虑将该类声明为静态类 ,但若是成员中包含公共的数据类型,此时便可以考虑将该类做成一个单例

单例模式

由于类中的数据,必须在实例化后堆栈才会为其分配变量的值,以及引用类型的地址,通过地址在静态存储区中也可访问其值。

那么,脚本文件每初始化一次,不管数据相不相同,已经是两个对象了,那么需要读取或者更新的字段就有可能出错。

所以,要保证外界可访问自身

需要在给类一个静态的公共自身成员,作为访问的中间桥梁

csharp 复制代码
private static T _instance;
public static T Instance => GetInstance();

要保证,单一对象

  • 在第一次访问时,new()
  • 如果已经实例化,使用之前实例化过的对象
csharp 复制代码
 private static T GetInstance()
 {
    if (_instance != null) return _instance;
    _instance = new T();
    _instance.Initialize();
    return _instance;
 }
        
public static void CreateSingleton()
{
    GetInstance();
}

访问时:SingletonAClass.Instance.Function();

就可以访问到唯一的function方法了。

单例类

实际在开发中,会根据需求做成单例类 的形式,使用不同的泛型约束 ,构造成不同的基类。

使用时,根据需求继承即可。

不继承Monobehavior的形式

在做一些公共数据库的时候,游戏频繁访问的一些实时数据,一般会把它做成单例,然后根据需求给数据一些 get set方法。

csharp 复制代码
 /// <summary>
    /// 通用单例。
    /// </summary>
    /// <typeparam name="T">泛型T。</typeparam>
    public abstract class Singleton<T> where T : Singleton<T>, new()
    {
        private static T _instance;
        public static T Instance => GetInstance();

        private static T GetInstance()
        {
            if (_instance != null) return _instance;
            _instance = new T();
            _instance.Initialize();
            return _instance;
        }
        
        public static void CreateSingleton()
        {
            GetInstance();
        }

        public static bool HasInstance()
        {
            return _instance != null;
        }

        public static void DestroySingleton()
        {
            _instance?.UnInitialize();
            _instance = null;
        }

        protected abstract void Initialize();
        protected abstract void UnInitialize();
    }

继承自Monobehavior的形式

最常见的,流程管理、总控的XXManager、XXController的脚本,一般会频繁调用,没有必要每次都实例化一个新的对象,实际会做成单例。约束绑定继承自Monobehavior

csharp 复制代码
/// <summary>
    /// 具备Unity完整生命周期的单例。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class UnitySingleton<T> : MonoBehaviour where T : MonoBehaviour
    {
        private static T _instance;

        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    var ins = FindObjectOfType<T>();
                    if (ins != null)
                    {
                        var obj = ins.gameObject;
                        obj.name = typeof(T).Name;
                        _instance = ins;
                        SingletonMgr.Retain(obj);
                        return Instance;
                    }

                    System.Type thisType = typeof(T);
                    string instName = thisType.Name;
                    GameObject go = SingletonMgr.GetGameObject(instName);
                    if (go == null)
                    {
                        go = GameObject.Find($"[{instName}]");
                        if (go == null)
                        {
                            go = new GameObject($"[{instName}]")
                            {
                                transform =
                                {
                                    position = Vector3.zero
                                }
                            };
                        }
                    }

                    _instance = go.GetComponent<T>();
                    if (_instance == null)
                    {
                        _instance = go.AddComponent<T>();
                    }

                    if (_instance == null)
                    {
                        Log.Error($"Can't create UnitySingleton<{typeof(T)}>");
                    }
                }

                return _instance;
            }
        }

        public static T Active()
        {
            return Instance;
        }

        public static bool IsValid => _instance != null;

        private bool CheckInstance()
        {
            if (this == Instance)
            {
                return true;
            }

            GameObject.Destroy(gameObject);
            return false;
        }

        protected virtual void OnLoad()
        {
        }

        public virtual void Awake()
        {
            if (CheckInstance())
            {
                OnLoad();
            }
#if UNITY_EDITOR
            Log.Debug($"UnitySingleton Instance:{typeof(T).Name}");
#endif
            GameObject tEngine = SingletonMgr.Root;
            if (tEngine != null)
            {
                this.gameObject.transform.SetParent(tEngine.transform);
            }
        }

        protected virtual void OnDestroy()
        {
            Release();
        }

        public static void Release()
        {
            if (_instance == null) return;
            SingletonMgr.Release(_instance.gameObject);
            _instance = null;
        }
    }
相关推荐
越甲八千10 小时前
重温设计模式--单例模式
单例模式·设计模式
Vincent(朱志强)10 小时前
设计模式详解(十二):单例模式——Singleton
android·单例模式·设计模式
重生之我在字节当程序员3 天前
如何实现单例模式?
单例模式
夕泠爱吃糖3 天前
如何实现单例模式?
单例模式
m0_607548763 天前
什么是单例模式
开发语言·javascript·单例模式
Am心若依旧4093 天前
[c++进阶(三)]单例模式及特殊类的设计
java·c++·单例模式
因特麦克斯3 天前
如何实现对象的克隆?如何实现单例模式?
c++·单例模式
狐拾叁6 天前
设计模式-创建者模式-单例模式(java版)
java·单例模式·设计模式
benben0446 天前
Unity3D仿星露谷物语开发5之角色单例模式
unity·单例模式·游戏引擎
Mr.136 天前
如何实现对象的克隆?如何实现单例模式?
c++·单例模式