继承MonoBehaviour单例模式基类

一、继承MonoBehaviour单例模式基类的特点

  • MonoBehaviour 不允许 new 创建实例,不存在公共构造函数破坏问题
  • 通常不涉及多线程,可忽略线程访问上锁

二、手动挂载式继承MonoBehaviour单例模式基类

1. 特点

  • 需要手动将脚本挂载到场景物体上
  • 依赖 Awake 初始化 instance
  • 容易破坏单例唯一性

2. 什么时候非常推荐使用它?

  • 该对象在场景中已经设置好(UI、音效、参数较多等)
  • 需要把场景上物体拖入(Canvas、AudioSource、相机)控制这些物体的跨场景持久化
  • Prefab 已经有复杂结构,不可能用 new GameObject 替代

3. 使用示例

不跨场景持久化

//写法一(推荐 简单方便)
using UnityEngine;
public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T Instance => instance;

    protected virtual void Awake()
    {
        instance = this as T; // 必须在 Awake 中初始化
    }
}

//写法二
using UnityEngine;
public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T Instance
    {
      get
      {
        return instance;
      }
    }
    protected virtual void Awake()
    {
        instance = this as T; // 必须在 Awake 中初始化
    }
}

跨场景持久化

using UnityEngine;
public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T Instance => instance;
    protected virtual void Awake()
    {
        if(instance != null)
        {
            Destroy(this.gameObject);
            return;
        }
        instance = this as T; // 必须在 Awake 中初始化
        DontDestroyOnLoad(this.gameObject);
    }
}

三、自动挂载式继承MonoBehaviour单例模式基类(推荐)

1. 特点

  • 无需手动挂载脚本
  • 在第一次访问 Instance 时自动创建物体并挂载脚本
  • 保证单例唯一性
  • 支持跨场景持久化(DontDestroyOnLoad

2. 什么时候非常推荐使用它?

  • 管理器不需要 Inspector 配置
  • 希望自动创建,使用即存在
  • GameManager、TimerManager、PoolManager(纯逻辑)

3. 使用示例

using UnityEngine;
public class SingletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    //选择在Instance属性里实现创建物体、添加脚本、场景不销毁逻辑,而不是Awkae里实现,是因为其它脚本调用该单例时直接访问Instance,如果Instance里没有创建物体逻辑,那么该单例的Awake也不会被Unity运行
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                // 动态创建物体
                GameObject obj = new GameObject(typeof(T).Name);
                // 为物体添加脚本
                instance = obj.AddComponent<T>();
                // 场景切换不销毁
                DontDestroyOnLoad(obj);
            }
            return instance;
        }
    }
}

posted @ 2025-12-09 14:02  高山仰止666  阅读(3)  评论(0)    收藏  举报