Unity | 工具类:单例总结
目录
一、常规单例
二、Unity单例
1. MonoBehaviour单例
2.Simple单例
一、常规单例
常规的单例模式是指在普通类中实现单例模式的方式,而不依赖于任何框架或引擎。这种单例模式在许多编程语言中都非常常见,其主要特点是:
- 单例类有一个私有的静态变量来保存唯一实例。
- 提供一个公有的静态方法(通常是
Instance
方法)来获取唯一实例。 - 将构造函数定义为私有,防止外部创建新的实例。
public class Singleton
{
// 用来保存唯一的实例
private static Singleton instance = null;
// 确保线程安全的锁对象
private static readonly object lockObj = new object();
// 私有构造函数,防止实例化
private Singleton()
{
}
// 获取唯一实例的公有静态方法
public static Singleton Instance
{
get
{
// 双重检查锁定(double-checked locking)
if (instance == null)
{
lock (lockObj)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
// 单例类中的方法示例
public void DoSomething()
{
Console.WriteLine("Singleton instance is doing something.");
}
}
二、Unity单例
1. MonoBehaviour单例
适合在需要动态创建单例对象的场合,并能处理场景切换等复杂情况。
优点:
- 懒加载:
Instance
属性只有在第一次访问时才会创建实例,这有助于减少不必要的开销。 - DontDestroyOnLoad:使用
DontDestroyOnLoad
保证实例在在场景切换时不被销毁。 - 防止重复创建单例:在销毁时设置
mIsDestroying
标记,防止对已销毁单例进行重复创建。
缺点:
- GameObject创建管理:它通过
new GameObject().AddComponent<MonoBehaviourSingleton>()
的方式创建实例,这在某些情况下过于灵活,可能导致难以管理和调试。 - 静态变量的潜在问题:如果游戏中对于对象销毁和创建的逻辑非常复杂,可能会因为静态变量状态互相干扰造成潜在的问题。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonoBehaviourSingleton : MonoBehaviour
{
static bool mIsDestroying; //判断销毁的静态变量
static MonoBehaviourSingleton mInstance;
public static MonoBehaviourSingleton Instance
{
get
{
if (mInstance == null)
{
if (mIsDestroying)
{
Debug.LogWarning("[MonoBehaviourSingleton] Instance '" + typeof(MonoBehaviourSingleton) +
"' already destroyed. Returning null.");
return null; //如果已销毁则跳出,防止嵌套调用
}
mInstance = new GameObject("[MonoBehaviourSingleton]").AddComponent<MonoBehaviourSingleton>();
DontDestroyOnLoad(mInstance.gameObject); //创建实例并设置为DontDestroyOnLoad
}
return mInstance;
}
}
public void Test()
{
Debug.Log("Test");
}
void OnDestroy()
{
mIsDestroying = true; //销毁时将标记变量设置为true,防止对已销毁单例进行重复创建
}
}
2.Simple单例
更直观简单,但需要确保对象在场景中存在且被正确管理,不适合频繁切换场景的情况。
优点:
- 更容易管理:不用手动创建GameObject,更多依赖于Unity编辑器来管理单例对象的创建。
- 避免重复实例:通过比较
instance
和this
,可以确保在同一场景中只存在一个实例。
缺点:
- 缺乏灵活性:不能像前一种方法那样灵活创建实例,必须确保在场景中包含该组件对应的对象。
- 潜在的实例丢失问题:如果
SimpleSingleton
对象不在初始场景中,可能会引发问题,如果有依赖该单例的其他代码在实例初始化之前执行,会出现空引用错误。
using UnityEngine;
public class SimpleSingleton : MonoBehaviour
{
private static SimpleSingleton instance;
public static SimpleSingleton Instance
{
get
{
if (instance == null)
{
Debug.LogError("Singleton instance has not been set. Make sure the singleton is properly instantiated.");
}
return instance;
}
}
protected virtual void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else if (instance != this)
{
Destroy(gameObject);
}
}
public void Test()
{
Debug.Log("Test");
}
}