阅读学习QFramework中的SingletonKit源码.
Singleton 普通类的单例
作为最常用的单例模块,通过继承单例泛型类来实现,需要私有构造;
//使用第一种接口单例方式 internal class Class2Singleton : Singleton { //记录被初始化的次数 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接口,方便对单例生命周期进行管理,留有给单例中数据进行初始化操作的方法。
/// /// 单例接口 /// public interface ISingleton { /// /// 单例初始化(继承当前接口的类都需要实现该方法) /// void OnSingletonInit(); } /// /// 普通类的单例 /// /// public abstract class Singleton<T> : 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() { } }
其中调用单例构造函数中相关内容:
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 class SingletonExample : MonoBehaviour { private void Start() { Class2Singleton.Instance.Log("我是第一种单例使用方式,第一次使用噢!"); Class2Singleton.Instance.Dispose(); //再次调用 Class2Singleton.Instance.Log("我是第一种单例使用方式,销毁之后,再次使用噢"); } }
MonoSingleton继承Mono的单例
MonoSingleton是继承Mono的单例类型,继承MonoBehaviour类和ISingleton接口,其实现方式与Singleton的内容相似
/// /// 静态类:MonoBehaviour类的单例 /// 泛型类:Where约束表示T类型必须继承MonoSingleton /// /// public abstract class MonoSingleton<T> : 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; } } }
来编写案例来使用Mono单例
namespace QFramework.Example { //使用MonoSingletonExample internal class Class2MonoSingleton : MonoSingleton { 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接口即可,当然,此处的接口作用就是对该类进行标记说说明,表明类是单例模式。下面看下两个工具类的具体实现:
/// /// 属性单例类 /// /// public static class SingletonProperty<T> 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; } } /// /// 继承Mono的属性单例? /// /// public static class MonoSingletonProperty<T> 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; } }
使用SignetonProperty来实现单例类:
internal class Class2SingletonProperty : ISingleton { private static int mIndex = 0; //静态单例属性 public static Class2SingletonProperty Instance { get { return SingletonProperty.Instance; } } public void OnSingletonInit() { mIndex++; } private Class2SingletonProperty() { } public void Dispose() { SingletonProperty.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.Instance; } } //继承ISingleton 接口实现方法 public void OnSingletonInit() { Debug.Log(name + "==" + "OnSingletonInit" ); } public void Dispose() { MonoSingletonProperty.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两个工具类。
变相的表明,想要加入单例圈子,需要继承此接口来打个标签。