1.non-MonoBehaviour 单例模式泛型基类

一、单例模式

1. 什么是单例模式

单例模式(Singleton Pattern)是一种设计模式。

作用:保证一个类在程序运行期间只有一个实例,并提供统一访问入口。

例如游戏中的管理类:

  • GameManager(游戏管理)
  • AudioManager(音频管理)
  • UIManager(UI管理)
  • DataManager(数据管理)
  • ResourceManager(资源管理)
    这些对象通常整个游戏只需要一个。

2. 为什么需要单例模式

如果普通创建对象:

复制代码
GameManager gm1 = new GameManager();
GameManager gm2 = new GameManager();

会产生多个管理对象。可能导致:

  • 数据不统一
  • 多个对象重复执行逻辑
  • 增加内存开销

二、非 MonoBehaviour 单例模式

1. 为什么 Manager 不继承 MonoBehaviour

Unity 中继承 MonoBehaviour 的类:

  • 需要挂载到 GameObject

  • 由 Unity 管理生命周期

  • 可以使用 Awake、Start、Update 等函数
    例如:

    public class Player : MonoBehaviour
    {

    }

2. 非 MonoBehaviour 单例特点

优点:

  • 不需要创建 GameObject
  • 不依赖 Unity 生命周期
  • 代码结构更加清晰
  • 适合程序框架层
    缺点:
  • 不能使用 Awake、Start、Update
  • 需要自己管理生命周期

三、泛型单例基类

1. 为什么使用泛型基类

如果每个 Manager 都单独写单例:每个管理器都需要重复编写。

2. 泛型单例基类实现

复制代码
public abstract class Singleton<T> where T : class, new()
{
    private static T instance;
    public static T Instance
    {
        get
        {
            instance ??= new T();
            return instance;
        }
    }
}

四、泛型约束

1. class 约束

复制代码
where T : class

表示:T 必须是引用类型。

原因:单例对象需要通过实例引用管理。

2. new() 约束

复制代码
where T : new()

表示:T 必须拥有无参数构造函数。因为内部需要:new T()创建对象。

五、Instance 属性

1. 作用

Instance 是单例访问入口。

第一次访问:

复制代码
Instance
 ↓
判断对象是否存在
 ↓
不存在
 ↓
创建对象
 ↓
返回对象

之后访问:

复制代码
Instance
 ↓
已有对象
 ↓
直接返回

2. 为什么使用属性

推荐:GameManager.Instance;

不推荐:GameManager.GetInstance();

原因:Instance 表示获取对象,更符合 C# 属性设计习惯。

六、具体 Manager 使用方式

1. 创建管理类

复制代码
public class GameManager : Singleton<GameManager>
{

}

继承:Singleton<GameManager>

即可拥有:GameManager.Instance

2. 添加功能

复制代码
public class AudioManager : Singleton<AudioManager>
{
    public void PlayMusic()
    {
        Debug.Log("播放音乐");
    }
}

调用:AudioManager.Instance.PlayMusic();

七、非 MonoBehaviour 单例注意事项

1. 不能使用 Unity 生命周期

不能:

复制代码
Awake()
Start()
Update()

如果需要初始化:

可以提供Initialize()

例如:GameManager.Instance.Initialize();

2. 避免过度使用

单例虽然方便:

复制代码
XXXManager.Instance

但是大量使用会造成:

  • 类之间耦合增加
  • 后期修改困难
    只用于真正需要全局唯一的对象。
相关推荐
Java后端的Ai之路10 小时前
06-React-Props
前端·react.js·前端框架
总要学点什么15 小时前
第55篇:空间分析-剖面分析——红线走大圆,剖面却按经纬直线采样
前端框架·gis·webgl·cesium·空间分析
samble16 小时前
从零搭建灌装监控系统(十八):自定义控件,三色灯与状态指示
c#·wpf·mvvm·modbus·工业控制
jun_bai16 小时前
使用Aspose实现word文档合并,内容替换
windows·c#·word
xcLeigh18 小时前
Unity基础:Instantiate实例化——在运行时动态创建游戏物体
游戏·unity·游戏引擎·教程·instantiate
字节暗面20 小时前
客户端上报不可信:游戏服务端数据校验与对局重演设计
c#·游戏开发·服务端校验·反作弊
Amos_Web20 小时前
Rspack 源码解析(二十一):Cacheable 与 Storage 如何持久化编译结果
前端·rust·前端框架
Amos_Web21 小时前
Rspack 源码解析(二十二):ExternalsPlugin 如何在 Factorize 阶段换掉整个模块
前端·rust·前端框架
chingho21 小时前
GitHub上这10个C#项目,不仅实用,还怪好玩的
c#·github·.net·开源项目
半亩码田1 天前
C#转Python第5.1篇:异步编程:asyncio vs async/await,语法相似但机制不同
开发语言·python·c#