初学者,自用笔记

建议不单独使用单例,改为单例注册表+DI框架集中管理

懒加载单例父类模板

by B站 超级依薇尔

//支持懒加载,awake之前已有对象调用,则提前创建单例
//空对象Manager命名应与脚本相同
public class TheManager<T> : MonoBehaviour where T : MonoBehaviour
{
    // 单例实例的公开访问属性
    public static T Instance
    {
        get
        {
            // 若实例为空,先在场景中查找该类型的组件
            if (_instance == null)
            {
                _instance = Object.FindAnyObjectByType<T>();
            }
          
            // 若场景中未找到实例,尝试创建
            if (_instance == null)
            {
                Debug.Log($"单例模式 {typeof(T).Name} 场景中不存在,尝试创建...");
            }
          
            // 若仍为空,进一步处理
            if (_instance == null)
            {
                // 查找带有 "Manager" 标签的游戏对象(用于挂载新组件)
                GameObject target = GameObject.FindGameObjectWithTag("Manager");
                if (target == null)
                {
                    // 若未找到标签为 "Manager" 的对象,创建一个新的游戏对象
                    target = new GameObject();
                    target.name = $"单例模式管理器 {typeof(T).Name}"; // 命名为具体管理器名称
                }
                // 若成功获取或创建了目标对象,给它添加 T 类型的组件(即单例实例)
                if (target != null)
                {
                    _instance = target.AddComponent<T>();
                }
            }
          
            return _instance;
        }
    
        set
        {
            // 若实例为空,将传入的值赋给实例(初始化)
            if (_instance == null)
            {
                _instance = value;
            }
            else
            {
                // 若已有实例,销毁新传入的重复实例(确保单例唯一性)
                if (value != null)
                {
                    Destroy(value);
                }
            }
        }
    }

    // 静态实例变量(私有,通过 Instance 属性访问)
    private static T _instance;

    // 唤醒时初始化单例
    private void Awake()
    {
        Instance = this as T;
        // 标记该对象在场景切换时不被销毁(确保单例跨场景存在)
        DontDestroyOnLoad(_instance.gameObject);
    }
}
  //用例public class GameManager : Singleton<GameManager>
  //调用为Manager.Instance,子类无需再次初始化