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

前言

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

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

单例模式

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

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

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

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

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;
        }
    }
相关推荐
C++忠实粉丝2 天前
Linux系统基础-多线程超详细讲解(5)_单例模式与线程池
linux·运维·服务器·c++·算法·单例模式·职场和发展
FANGhelloworld2 天前
C++面向对象设计模式——单例模式
c++·单例模式·设计模式
土了个豆子的2 天前
单例模式的概念和用处
单例模式
飞升不如收破烂~3 天前
在Spring框架中,容器管理的bean可以有不同的作用域(scope),其中最常用的两种是单例(singleton)和原型(prototype)。
spring·单例模式·原型模式
晨曦丿3 天前
设计模式之——单例模式
c++·单例模式·设计模式
徐子童4 天前
多线程案例---单例模式
java·单例模式·设计模式
Good_tea_h5 天前
线程安全的单例模式(Singleton)。
单例模式
Tang Paofan5 天前
C++单例模式
java·c++·单例模式
nice666605 天前
DAO模式及单例模式
java·数据库·sql·mysql·单例模式·idea
慕木沐6 天前
【创建型】单例模式
java·开发语言·单例模式