/**************************************************************************** * Copyright (c) 2017 ~ 2021 liangxie MIT License * * https://github.com/liangxiegame/SingletonKit ****************************************************************************/ using System; using System.Reflection; using UnityEngine; namespace QFramework { /// /// 单例接口 /// public interface ISingleton { /// /// 单例初始化(继承当前接口的类都需要实现该方法) /// void OnSingletonInit(); } /// /// 普通类的单例 /// /// public abstract class Singleton : ISingleton where T : Singleton { /// /// 静态实例 /// protected static T mInstance; /// /// 标签锁:确保当一个线程位于代码的临界区时,另一个线程不进入临界区。 /// 如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放 /// static object mLock = new object(); /// /// 静态属性 /// public static T Instance { get { lock (mLock) { if (mInstance == null) { mInstance = SingletonCreator.CreateSingleton(); } } return mInstance; } } /// /// 资源释放 /// public virtual void Dispose() { mInstance = null; } /// /// 单例初始化方法 /// public virtual void OnSingletonInit() { } } /// /// 属性单例类 /// /// public static class SingletonProperty where T : class, ISingleton { /// /// 静态实例 /// private static T mInstance; /// /// 标签锁 /// private static readonly object mLock = new object(); /// /// 静态属性 /// public static T Instance { get { lock (mLock) { if (mInstance == null) { mInstance = SingletonCreator.CreateSingleton(); } } return mInstance; } } /// /// 资源释放 /// public static void Dispose() { mInstance = null; } } /// /// 普通单例创建类 /// internal static class SingletonCreator { static T CreateNonPublicConstructorObject() where T : class { var type = typeof(T); // 获取私有构造函数 var constructorInfos = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic); // 获取无参构造函数 var ctor = Array.Find(constructorInfos, c => c.GetParameters().Length == 0); if (ctor == null) { throw new Exception("Non-Public Constructor() not found! in " + type); } return ctor.Invoke(null) as T; } public static T CreateSingleton() where T : class, ISingleton { var type = typeof(T); var monoBehaviourType = typeof(MonoBehaviour); if (monoBehaviourType.IsAssignableFrom(type)) { return CreateMonoSingleton(); } else { var instance = CreateNonPublicConstructorObject(); instance.OnSingletonInit(); return instance; } } /// /// 单元测试模式 标签 /// public static bool IsUnitTestMode { get; set; } /// /// 查找Obj(一个嵌套查找Obj的过程) /// /// 父节点 /// 拆分后的路径节点 /// 下标 /// true /// 不要销毁 标签 /// private static GameObject FindGameObject(GameObject root, string[] subPath, int index, bool build, bool dontDestroy) { GameObject client = null; if (root == null) { client = GameObject.Find(subPath[index]); } else { var child = root.transform.Find(subPath[index]); if (child != null) { client = child.gameObject; } } if (client == null) { if (build) { client = new GameObject(subPath[index]); if (root != null) { client.transform.SetParent(root.transform); } if (dontDestroy && index == 0 && !IsUnitTestMode) { GameObject.DontDestroyOnLoad(client); } } } if (client == null) { return null; } return ++index == subPath.Length ? client : FindGameObject(client, subPath, index, build, dontDestroy); } /// /// 泛型方法:创建MonoBehaviour单例 /// /// /// public static T CreateMonoSingleton() where T : class, ISingleton { T instance = null; var type = typeof(T); //判断T实例存在的条件是否满足 if (!IsUnitTestMode && !Application.isPlaying) return instance; //判断当前场景中是否存在T实例 instance = UnityEngine.Object.FindObjectOfType(type) as T; if (instance != null) { instance.OnSingletonInit(); return instance; } //MemberInfo:获取有关成员属性的信息并提供对成员元数据的访问 MemberInfo info = typeof(T); //获取T类型 自定义属性,并找到相关路径属性,利用该属性创建T实例 var attributes = info.GetCustomAttributes(true); foreach (var atribute in attributes) { var defineAttri = atribute as MonoSingletonPath; if (defineAttri == null) { continue; } instance = CreateComponentOnGameObject(defineAttri.PathInHierarchy, true); break; } //如果还是无法找到instance 则主动去创建同名Obj 并挂载相关脚本 组件 if (instance == null) { var obj = new GameObject(typeof(T).Name); if (!IsUnitTestMode) UnityEngine.Object.DontDestroyOnLoad(obj); instance = obj.AddComponent(typeof(T)) as T; } instance.OnSingletonInit(); return instance; } /// /// 在GameObject上创建T组件(脚本) /// /// /// 路径(应该就是Hierarchy下的树结构路径) /// 不要销毁 标签 /// private static T CreateComponentOnGameObject(string path, bool dontDestroy) where T : class { var obj = FindGameObject(path, true, dontDestroy); if (obj == null) { obj = new GameObject("Singleton of " + typeof(T).Name); if (dontDestroy && !IsUnitTestMode) { UnityEngine.Object.DontDestroyOnLoad(obj); } } return obj.AddComponent(typeof(T)) as T; } /// /// 查找Obj(对于路径 进行拆分) /// /// 路径 /// true /// 不要销毁 标签 /// private static GameObject FindGameObject(string path, bool build, bool dontDestroy) { if (string.IsNullOrEmpty(path)) { return null; } var subPath = path.Split('/'); if (subPath == null || subPath.Length == 0) { return null; } return FindGameObject(null, subPath, 0, build, dontDestroy); } } /// /// 静态类:MonoBehaviour类的单例 /// 泛型类:Where约束表示T类型必须继承MonoSingleton /// /// public abstract class MonoSingleton : MonoBehaviour, ISingleton where T : MonoSingleton { /// /// 静态实例 /// protected static T mInstance; /// /// 静态属性:封装相关实例对象 /// public static T Instance { get { if (mInstance == null && !mOnApplicationQuit) { mInstance = SingletonCreator.CreateMonoSingleton(); } return mInstance; } } /// /// 实现接口的单例初始化 /// public virtual void OnSingletonInit() { } /// /// 资源释放 /// public virtual void Dispose() { if (SingletonCreator.IsUnitTestMode) { var curTrans = transform; do { var parent = curTrans.parent; DestroyImmediate(curTrans.gameObject); curTrans = parent; } while (curTrans != null); mInstance = null; } else { Destroy(gameObject); } } /// /// 当前应用程序是否结束 标签 /// protected static bool mOnApplicationQuit = false; /// /// 应用程序退出:释放当前对象并销毁相关GameObject /// protected virtual void OnApplicationQuit() { mOnApplicationQuit = true; if (mInstance == null) return; Destroy(mInstance.gameObject); mInstance = null; } /// /// 释放当前对象 /// protected virtual void OnDestroy() { mInstance = null; } /// /// 判断当前应用程序是否退出 /// public static bool IsApplicationQuit { get { return mOnApplicationQuit; } } } /// /// MonoSingleton路径 /// [AttributeUsage(AttributeTargets.Class)] //这个特性只能标记在Class上 public class MonoSingletonPath : Attribute { private string mPathInHierarchy; public MonoSingletonPath(string pathInHierarchy) { mPathInHierarchy = pathInHierarchy; } public string PathInHierarchy { get { return mPathInHierarchy; } } } /// /// 继承Mono的属性单例? /// /// public static class MonoSingletonProperty where T : MonoBehaviour, ISingleton { private static T mInstance; public static T Instance { get { if (null == mInstance) { mInstance = SingletonCreator.CreateMonoSingleton(); } return mInstance; } } public static void Dispose() { if (SingletonCreator.IsUnitTestMode) { UnityEngine.Object.DestroyImmediate(mInstance.gameObject); } else { UnityEngine.Object.Destroy(mInstance.gameObject); } mInstance = null; } } /// /// 如果跳转到新的场景里已经有了实例,则不创建新的单例(或者创建新的单例后会销毁掉新的单例) /// /// public abstract class PersistentMonoSingleton : MonoBehaviour where T : Component { protected static T mInstance; protected bool mEnabled; /// /// Singleton design pattern /// /// The instance. public static T Instance { get { if (mInstance == null) { mInstance = FindObjectOfType(); if (mInstance == null) { var obj = new GameObject(); mInstance = obj.AddComponent(); } } return mInstance; } } /// /// On awake, we check if there's already a copy of the object in the scene. If there's one, we destroy it. /// protected virtual void Awake() { if (!Application.isPlaying) { return; } if (mInstance == null) { //If I am the first instance, make me the Singleton mInstance = this as T; DontDestroyOnLoad(transform.gameObject); mEnabled = true; } else { //If a Singleton already exists and you find //another reference in scene, destroy it! if (this != mInstance) { Destroy(this.gameObject); } } } } /// /// 如果跳转到新的场景里已经有了实例,则删除已有示例,再创建新的实例 /// /// public class ReplaceableMonoSingleton : MonoBehaviour where T : Component { protected static T mInstance; public float InitializationTime; /// /// Singleton design pattern /// /// The instance. public static T Instance { get { if (mInstance == null) { mInstance = FindObjectOfType(); if (mInstance == null) { GameObject obj = new GameObject(); obj.hideFlags = HideFlags.HideAndDontSave; mInstance = obj.AddComponent(); } } return mInstance; } } /// /// On awake, we check if there's already a copy of the object in the scene. If there's one, we destroy it. /// protected virtual void Awake() { if (!Application.isPlaying) { return; } InitializationTime = Time.time; DontDestroyOnLoad(this.gameObject); // we check for existing objects of the same type T[] check = FindObjectsOfType(); foreach (T searched in check) { if (searched != this) { // if we find another object of the same type (not this), and if it's older than our current object, we destroy it. if (searched.GetComponent>().InitializationTime < InitializationTime) { Destroy(searched.gameObject); } } } if (mInstance == null) { mInstance = this as T; } } } }