yorickyao
yorickyao
发布于 2025-10-14 / 22 阅读
0
0

🧩基于Unity的简单框架工具类(1)

单例

1、概述

单例模式是游戏开发中最常用的设计模式之一,用于确保某个类只有一个实例,并提供全局访问点。本框架提供了两种单例基类,分别适用于不同的使用场景。

2、MonoSingleton<T> - 基于MonoBehaviour的单例

设计目的

MonoSingleton<T>专为需要挂载到游戏场景中的组件设计,适用于需要依赖Unity生命周期方法的单例类。

使用场景

  • 需要访问Unity组件(如Transform、Renderer等)的单例

  • 需要使用Unity生命周期方法(如Update、Start等)的单例

  • 需要在Inspector中配置参数的单例

  • 需要与其他GameObject进行交互的单例

实现特点

  1. 自动场景管理​:如果实例不存在,会自动在场景中创建GameObject并挂载组件

  2. 防止重复创建​:通过Awake方法检测并销毁重复实例

  3. 场景持久化​:实例会随着场景加载而自动创建

  4. 线程安全​:在Unity主线程中安全使用

MonoSingleton代码

using UnityEngine;

/// <summary>
/// 通用 MonoBehaviour 单例基类,适用于需要挂载到场景中的组件类型。
/// </summary>
/// <typeparam name="T">单例类型参数。</typeparam>
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    private static T _instance;

    // 获取当前类型的单例实例。
    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<T>();
                if (_instance == null)
                {
                    var obj = new GameObject(typeof(T).Name);
                    _instance = obj.AddComponent<T>();
                }
            }
            return _instance;
        }
    }

    // 初始化单例实例。
    protected virtual void Awake()
    {
        if (_instance == null)
        {
            _instance = this as T;
        }
        else if (_instance != this)
        {
            Destroy(gameObject);
        }
    }
}

代码示例

public class GameManager : MonoSingleton<GameManager>
{
    private int playerScore = 0;
    
    protected override void Awake()
    {
        base.Awake(); // 必须调用基类Awake方法
        // 初始化代码
    }
    
    public void AddScore(int points)
    {
        playerScore += points;
    }
    
    public int GetScore()
    {
        return playerScore;
    }
}

// 使用示例
GameManager.Instance.AddScore(100);

3、Singleton<T> - 普通单例类

设计目的

Singleton<T>适用于不需要依赖Unity引擎的纯C#类,提供更轻量级的单例实现。

使用场景

  • 数据管理类(如配置管理器、存档管理器)

  • 服务类(如网络服务、音频服务)

  • 工具类(如本地化管理器、事件系统)

  • 任何不需要Unity组件功能的单例类

实现特点

  • 线程安全​:使用Lazy<T>实现线程安全的延迟初始化

  • 轻量级​:不依赖Unity引擎,性能开销更小

  • 严格单例​:通过保护构造函数防止外部实例化

  • 延迟加载​:实例在第一次访问时才会创建

Singleton代码

using System;

/// <summary>
/// 通用单例基类,提供线程安全的实例访问方式,适用于非 MonoBehaviour 类型的类。
/// </summary>
/// <typeparam name="T">单例类型参数</typeparam>
public abstract class Singleton<T> where T : class, new()
{
    private static readonly Lazy<T> _instance = new(() => new T());

    // 获取当前类型的单例实例。
    public static T Instance => _instance.Value;

    // 受保护的构造函数,防止外部实例化。
    protected Singleton() { }
}

代码示例

public class ConfigManager : Singleton<ConfigManager>
{
    private Dictionary<string, string> configData;
    
    protected ConfigManager()
    {
        // 初始化配置数据
        configData = new Dictionary<string, string>();
        LoadConfig();
    }
    
    private void LoadConfig()
    {
        // 加载配置文件的逻辑
    }
    
    public string GetConfigValue(string key)
    {
        return configData.ContainsKey(key) ? configData[key] : null;
    }
}

// 使用示例
string value = ConfigManager.Instance.GetConfigValue("GameDifficulty");

4、使用建议

  1. 选择指南​:

    • 如果需要使用Unity组件或生命周期方法,选择 MonoSingleton<T>

    • 如果是纯数据或逻辑类,选择 Singleton<T>

  2. 最佳实践​:

    • 避免在单例中保存大量数据,以免造成内存压力

    • 单例类应该职责单一,遵循单一职责原则

    • 考虑使用依赖注入来管理单例的生命周期

  3. 注意事项​:

    • MonoSingleton<T>在场景切换时会被销毁,需要手动处理持久化需求

    • Singleton<T>在整个应用程序生命周期内存在,需要注意内存管理

    • 两种单例都不适合用于需要频繁创建和销毁的对象

这两种单例实现为Unity游戏开发提供了灵活而强大的基础工具,开发者可以根据具体需求选择合适的单例类型。


评论