1. 使用不继承MonoBehaviour单例基类的目的
- 避免重复编写相同的单例模式代码
- 让项目中的管理器类结构更统一、可维护
2. 缺点
- 构造函数问题(必须解决 公共构造函数破坏单例唯一性)
- 如果单例构造函数未设为
private,外部可能创建多个实例,破坏单例唯一性。需要将单例构造函数设为private,单例基类通过反射创建单例实例,但性能开销较大
- 多线程问题(通常不需要解决 Unity 本质是单线程主循环框架,你的管理器一般只在主线程初始化一次,多线程并不会访问到你的单例)
- 在多线程环境下,如果多个线程同时访问实例创建逻辑,可能导致创建多个实例,需要加锁保证线程安全。
- 不推荐使用不继承MonoBehaviour单例基类实现内部物体跨场景,可以使用继承MonoBehaviour单例基类,再把物体拖入Inspect中,UIManager就可以将Canvas拖入
3. 不继承 MonoBehaviour 的单例基类实现(解决构造函数问题)
using System;
using System.Reflection;
using UnityEngine;
/// <summary>
/// 单例模式基类,避免代码冗余
/// </summary>
/// <typeparam name="T"> T:class便于使用反射创建实例 </typeparam>
public abstract class BaseManager<T> where T : class
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
//反射创建实例
// 方法一 通过Activator.CreateInstance创建实例(推荐)
instance = (T)Activator.CreateInstance(typeof(T), true);
// 方法二 通过单例私有构造函数创建实例(不推荐)
//Type type = typeof(T);
//ConstructorInfo constructor = type.GetConstructor(
// BindingFlags.Instance | BindingFlags.NonPublic,
// null,
// Type.EmptyTypes,
null);
//if (constructor != null)
//{
// instance = (T)constructor.Invoke(null);
//}
//else
//{
// Debug.LogError("没有找到对应的私有构造函数");
//}
}
//返回创建的单例实例
return instance;
}
}
}
4. 不继承 MonoBehaviour 的单例基类实现(解决线程安全问题)
using System;
using System.Reflection;
using UnityEngine;
/// <summary>
/// 单例模式基类 避免代码冗余
/// </summary>
/// <typeparam name="T">继承class类 用于创建实例</typeparam>
public abstract class BaseManager<T> where T : class
{
private static T instance;
//用于加锁的对象
protected static readonly object lockObj = new object();
//属性的方式
public static T Instance
{
get
{
if (instance == null)
{
lock (lockObj)
{
if (instance == null)
{
//通过反射创建实例
//方法一 通过Activator.CreateInstance直接实例化 参数true:允许反射实例化私有构造函数(推荐使用)
instance = (T)Activator.CreateInstance(typeof(T), true);
//方法二 利用反射获取私有构造函数 通过私有构造函数实例对象(不推荐使用)
//Type type = typeof(T);
//ConstructorInfo constructor = type.GetConstructor(
// BindingFlags.Instance | BindingFlags.NonPublic, //表示成员私有方法
// null, //表示没有绑定对象
// Type.EmptyTypes, //表示没有参数
// null); //表示没有参数修饰符
//if (constructor != null)
//{
// instance = (T)constructor.Invoke(null);
//}
//else
//{
// Debug.LogError("没有得到相应的私有构造函数");
//}
}
}
}
return instance;
}
}
}