SingletonKit单例源码阅读学习

news/2024/10/2 8:42:17

阅读学习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("我是第一种单例使用方式,销毁之后,再次使用噢");}}

image-20240617170633493

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();}}
}

image-20240617175832663

5s后对单例对象进行释放:

img

使用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,由于C#中只支持class单继承,如果我想要此单例类再继承一个Mono相关的类,那么将增加很多的编码工作。

image-20240617184607191

而使用MonoSingletonProperty之后是继承接口,可以方便继承Mono相关的类。

那么使用ISingleton接口的作用是什么?

作为泛型约束,也就是说想要成为单例的类必须要继承ISingleton接口才可以使用MonoSingletonProperty/SingletonProperty两个工具类。

变相的表明,想要加入单例圈子,需要继承此接口来打个标签。

image-20240617185704194

image-20240617185718773

UML图

image-20240617201339124

源码地址:https://github.com/liangxiegame/SingletonKit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/44854.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

复习加总结

Markdown学习 标题 三级标题 四级标题 字体 粗体: 俩*hello,World 斜体:一个**hello,World* 斜体加粗三个* hello,World 删除线:两个~ hello,World 引用始作俑者没有受罚,仅仅是受害者再受害一次罢了,最多也就是管理/梦境支配者的人类在人类世界的走狗棋子被带走,毫无…

HandyControl 使用内置Command 执行无效问题

HandyControl 使用内置Command 执行无效问题HandyControl 中通过查阅代码HandyControl_Shared 共享项目中,Interactivity/Commands 目录下,存在着一些内置 Command,开心发现还有关闭窗体,最小化等系统级别常用命令。 CloseWindowCommand.cs ControlCommands.cs OpenLinkCom…

UE5——GAS实现连招的一种方案

前言 最近因为在研究多人联机同步下的动作同步,在Google上很幸运搜到了一篇日本博主写的GAS编写连招的方案,于是就打算贴出来分享一下,顺便讲讲实现的心得: 【UE5】GamePlayAbilitySystemによるコンボ攻撃の実装とそれに利用する小ネタ 前編【GAS】 【UE5】GamePlayAbilit…

cuda程序优化-3.通信简介

GPU进行卡间通信/多机通信的算法简介硬件结构 CPU<->GPU: 通过PCIe进行通信 GPU<->GPU: NVLink, 通过Switch桥接器辅助访问其他卡的HBM 多机通信: InfiniBand with GPU Direct RDMA(简称GDRDMA), 需要专用网卡卡间通信-Ring AllReduce nvidia文档 1. 初始状态卡数:…

【Azure App Service】遇见az命令访问HTTPS App Service 时遇见SSL证书问题,暂时跳过证书检查的办法

SSL: CERITIFICATE_VERIFY_FAILED certificate verify failed: unable to get local issuer certificate问题描述 访问App Service的高级工具KUDU站点的URL,遇见无法访问,在通过az webapp deploy发布时候,也遇见SSL错误 (SSL: CERITIFICATE_VERIFY_FAILED certificate verif…

计算机组成原理学习 Part 2

系统总线 总线 连接各个部件的信息传输线,是各个部件共享的传输介质 结构单总线 面向 CPU 的双总线 以存储器为中心的双总线 三总线 三总线的又一形式 四总线分类片内总线:芯片内部的总线 系统总线:计算机各部件之间的信息传输线\[ \begin{cases}数据总线 & 双向 \quad…

NumPy 差分、最小公倍数、最大公约数、三角函数详解

NumPy 助你处理数学问题:计算序列的差分用`np.diff()`,示例返回`[5, 10, -20]`;找最小公倍数(LCM)用`np.lcm()`,数组示例返回`18`;最大公约数(GCD)用`np.gcd.reduce()`,数组示例返回`4`;三角函数如`np.sin()`,`np.deg2rad()`用于角度弧度转换。别忘了`np.arcsin()`等反…

LVGL line组件

目录Line(线条)的概念线条组件的使用创建线条对象设置点数组确定y轴的方向(可选)设置线条风格(可选)创建风格设置风格将创建好的线段组件添加到父对象上示例代码:运行结果 Line(线条)的概念线条组件的使用 创建线条对象设置点数组 line组件的实现原理就是通过连接两个…