阅读学习QFramwork中的SingletonKit源码。
Singleton 普通类的单例
作为最常用的单例模块,通过继承单例泛型类来实现,需要私有构造;
//使用第一种接口单例方式internal class Class2Singleton : Singleton<Class2Singleton>{//记录被初始化的次数private static int mIndex = 0;//私有构造private Class2Singleton(){}public override void OnSingletonInit(){mIndex++;Log(mIndex.ToString());}public void Log(string content){Debug.Log("Class2Singleton" + content);}}
看一下父类的代码内容,首先是ISingleton接口,方便对单例生命周期进行管理,留有给单例中数据进行初始化操作的方法。
/// <summary>/// 单例接口/// </summary>public interface ISingleton{/// <summary>/// 单例初始化(继承当前接口的类都需要实现该方法)/// </summary>void OnSingletonInit();}/// <summary>/// 普通类的单例/// </summary>/// <typeparam name="T"></typeparam>public abstract class Singleton<T> : ISingleton where T : Singleton<T>{/// <summary>/// 静态实例/// </summary>protected static T mInstance;/// <summary>/// 标签锁:确保当一个线程位于代码的临界区时,另一个线程不进入临界区。/// 如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放/// </summary>static object mLock = new object();/// <summary>/// 静态属性/// </summary>public static T Instance{get{lock (mLock){if (mInstance == null){//调用单例构造器实例化单例对象mInstance = SingletonCreator.CreateSingleton<T>();}}return mInstance;}}/// <summary>/// 资源释放/// </summary>public virtual void Dispose(){mInstance = null;}/// <summary>/// 单例初始化方法/// </summary>public virtual void OnSingletonInit(){}}
其中调用单例构造函数中相关内容:
internal static class SingletonCreator{//通过反射来进行对象构造static T CreateNonPublicConstructorObject<T>() 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<T>() where T : class, ISingleton{var type = typeof(T);var monoBehaviourType = typeof(MonoBehaviour);if (monoBehaviourType.IsAssignableFrom(type)){return CreateMonoSingleton<T>();}else{var instance = CreateNonPublicConstructorObject<T>();instance.OnSingletonInit();return instance;}}//······
}
编写案例调用单例;
public class SingletonExample : MonoBehaviour{private void Start(){Class2Singleton.Instance.Log("我是第一种单例使用方式,第一次使用噢!");Class2Singleton.Instance.Dispose();//再次调用Class2Singleton.Instance.Log("我是第一种单例使用方式,销毁之后,再次使用噢");}}
MonoSingleton继承Mono的单例
MonoSingleton是继承Mono的单例类型,继承MonoBehaviour类和ISingleton接口,其实现方式与Singleton的内容相似
/// <summary>/// 静态类:MonoBehaviour类的单例/// 泛型类:Where约束表示T类型必须继承MonoSingleton<T>/// </summary>/// <typeparam name="T"></typeparam>public abstract class MonoSingleton<T> : MonoBehaviour, ISingleton where T : MonoSingleton<T>{/// <summary>/// 静态实例/// </summary>protected static T mInstance;/// <summary>/// 静态属性:封装相关实例对象/// </summary>public static T Instance{get{if (mInstance == null && !mOnApplicationQuit){mInstance = SingletonCreator.CreateMonoSingleton<T>();}return mInstance;}}/// <summary>/// 实现接口的单例初始化/// </summary>public virtual void OnSingletonInit(){}/// <summary>/// 资源释放/// </summary>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);}}/// <summary>/// 当前应用程序是否结束 标签/// </summary>protected static bool mOnApplicationQuit = false;/// <summary>/// 应用程序退出:释放当前对象并销毁相关GameObject/// </summary>protected virtual void OnApplicationQuit(){mOnApplicationQuit = true;if (mInstance == null) return;Destroy(mInstance.gameObject);mInstance = null;}/// <summary>/// 释放当前对象/// </summary>protected virtual void OnDestroy(){mInstance = null;}/// <summary>/// 判断当前应用程序是否退出/// </summary>public static bool IsApplicationQuit{get { return mOnApplicationQuit; }}}
来编写案例来使用Mono单例
namespace QFramework.Example
{//使用MonoSingletonExampleinternal class Class2MonoSingleton : MonoSingleton<Class2MonoSingleton>{public override void OnSingletonInit(){Debug.Log(name + "---" + "OnSingletonInit");}private void Awake(){Debug.Log(name + "---" + "awake");}private void Start(){Debug.Log(name + "---" + "start");}protected override void OnDestroy(){base.OnDestroy();Debug.Log(name + "---" + "OnDestroy");}}public class MonoSingletonExample : MonoBehaviour{private IEnumerator Start(){var instance = Class2MonoSingleton.Instance;yield return new WaitForSeconds(5.0f);instance.Dispose();}}
}
5s后对单例对象进行释放:
使用MonoSingletonProperty/SingletonProperty两个工具类来封装单例,在实现设置单例类时候不需要再继承 MonoSingleton 或 Singleton ,只需要继承ISingleton接口即可,当然,此处的接口作用就是对该类进行标记说说明,表明类是单例模式。下面看下两个工具类的具体实现:
/// <summary>/// 属性单例类/// </summary>/// <typeparam name="T"></typeparam>public static class SingletonProperty<T> where T : class, ISingleton{/// <summary>/// 静态实例/// </summary>private static T mInstance;/// <summary>/// 标签锁/// </summary>private static readonly object mLock = new object();/// <summary>/// 静态属性/// </summary>public static T Instance{get{lock (mLock){if (mInstance == null){mInstance = SingletonCreator.CreateSingleton<T>();}}return mInstance;}}/// <summary>/// 资源释放/// </summary>public static void Dispose(){mInstance = null;}}/// <summary>/// 继承Mono的属性单例?/// </summary>/// <typeparam name="T"></typeparam>public static class MonoSingletonProperty<T> where T : MonoBehaviour, ISingleton{private static T mInstance;public static T Instance{get{if (null == mInstance){mInstance = SingletonCreator.CreateMonoSingleton<T>();}return mInstance;}}public static void Dispose(){if (SingletonCreator.IsUnitTestMode){UnityEngine.Object.DestroyImmediate(mInstance.gameObject);}else{UnityEngine.Object.Destroy(mInstance.gameObject);}mInstance = null;}}
使用SignetonProperty来实现单例类:
internal class Class2SingletonProperty : ISingleton{private static int mIndex = 0;//静态单例属性public static Class2SingletonProperty Instance{get { return SingletonProperty<Class2SingletonProperty>.Instance; }}public void OnSingletonInit(){mIndex++;}private Class2SingletonProperty(){}public void Dispose(){SingletonProperty<Class2SingletonProperty>.Dispose();}public void Log(string content){Debug.Log("Class2SingletonProperty" + mIndex + "---" + content);}}public class SingletonPropertyExample : MonoBehaviour{private void Start(){Class2SignetonProperty.Instance.Log("Hello Tony!");Class2SignetonProperty.Instance.Dispose();Class2SignetonProperty.Instance.Log("Hello TonyChang");}}
其运行结果和第一个单例实现案例结果相同。
使用MonoSingletonProperty实现单例类:
internal class Class2MonoSingletonProperty : MonoBehaviour, ISingleton{//仅仅需要声明静态属性即可public static Class2MonoSingletonProperty Instance{get { return MonoSingletonProperty<Class2MonoSingletonProperty>.Instance; }}//继承ISingleton 接口实现方法public void OnSingletonInit(){Debug.Log(name + "==" + "OnSingletonInit" );}public void Dispose(){MonoSingletonProperty<Class2MonoSingletonProperty>.Dispose();}private void Awake(){Debug.Log(name + "==" + "Awake" );}private void Start(){Debug.Log(name + "==" + "Start" );}private void OnDestroy(){Debug.Log(name + "==" + "OnDestroy" );}}public class MonoSingletonPropertyExample:MonoBehaviour{private IEnumerator Start(){var instance = Class2MonoSingletonProperty.Instance;yield return new WaitForSeconds(5.0f);instance.Dispose();}}
其运行结果和第二个继承Mono的单例实现案例结果相同。
相关问题:
那么不免产生疑问--使用MonoSingletonProperty/SingletonProperty两个工具类来封装单例好处是什么?或者说解决什么问题。
我们看不使用MonoSingletonProperty实现单例,需要继承抽象类MonoSingleton
而使用MonoSingletonProperty之后是继承接口,可以方便继承Mono相关的类。
那么使用ISingleton接口的作用是什么?
作为泛型约束,也就是说想要成为单例的类必须要继承ISingleton接口才可以使用MonoSingletonProperty/SingletonProperty两个工具类。
变相的表明,想要加入单例圈子,需要继承此接口来打个标签。
UML图
源码地址:https://github.com/liangxiegame/SingletonKit