首页 > 编程语言 >SingletonKit单例源码阅读学习

SingletonKit单例源码阅读学习

时间:2024-06-17 20:20:55浏览次数:14  
标签:mInstance void public 源码 static 单例 SingletonKit Log

阅读学习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
{
    //使用MonoSingletonExample
    internal 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

标签:mInstance,void,public,源码,static,单例,SingletonKit,Log
From: https://www.cnblogs.com/TonyCode/p/18253139

相关文章

  • AOP切面的实现原理【底层源码】
    AOP是基于IOC的Bean加载来实现的,将切面类的所有切面方法根据使用的注解生成对应的Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备这里我们可以很明确的知道,AOP也是在Bean容器中被Spring管理的,根据初始化过程打断点定位......
  • AOP代理的创建【底层源码】
    代理的创建(源码)创建代理的方法是postProcessAfterInitialization:如果Bean被子类标识为代理,则使用配置的拦截器创建一个代理源码参考:AOP切面底层原理【底层源码】-postProcessAfterInitialization源码部分wrapIfNecessary方法主要用于判断是否需要创建代理,如果bean能......
  • 基于springboot的南门桥社区疫情防疫系统-48138(免费领源码+数据库)可做计算机毕业设计J
    Springboot南门桥社区疫情防疫系统的设计与实现摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对南门桥社区疫情防疫系统等问题,对南门桥社区......
  • 生成式 AI 服务应用之Langchain 和 DashScope Reranker 彻底改变您的文档检索过程(教程
    介绍在当今信息泛滥的时代,找到所需的确切文档似乎是一件不可能完成的事情。传统搜索引擎经常让您在无关内容中苦苦挣扎,浪费宝贵的时间。但不要担心,因为有一对强大的组合正在等待彻底改变您的搜索体验:Langchain和DashScopeReranker。推荐文章《如何使用CodeLlama......
  • 精选了10个Python实战项目(附源码),拿走即用!
    ① 猜字游戏在这个游戏中,你必须一个字母一个字母的猜出秘密单词。如果你猜错了一个字母,你将丢掉一条命。正如游戏名那样,你需要仔细选择字母,因为你的生命数量非常有限。importrandom#生命次数lives=3#神秘单词,随机选择words=['pizza','fairy','teeth','......
  • 基于Java+Vue的采购管理系统:实现采购业务数字化(全套源码)
    前言:采购管理系统是一个综合性的管理平台,旨在提高采购过程的效率、透明度,并优化供应商管理。以下是对各个模块的详细解释:一、供应商准入供应商注册:供应商通过在线平台进行注册,填写基本信息和资质文件。资质审核:系统对供应商提交的资质文件进行自动或人工审核,确保供应商符......
  • SpringBoot开发Activiti工作流实现审批流程(全套源码)
    前言activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,一套完整并且实际运用在多套项目中的案例,满足日常业务流程审批需求。一、项目形式springboot+vue+activiti集成了activiti在线编辑器,流行的前后端分离部署开发模式,快速开发平台,可插拔工作流服务。工......
  • 俄罗斯方块小游戏(附源码)
    游戏展示一.导包importturtleimportrandom二.定义一个Block类定义一个Block类,用于表示游戏中的方块,包含颜色和形状。classBlock:def__init__(self,color,tiles):self.color=colorself.tiles=tiles三.定义了7个不同的Block对象定......
  • ThreadLocal 核心源码分析
    ThreadLocal简介多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证和规避多线程访问出......
  • 基于springboot的球队训练信息管理系统源码数据库
    传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装球队训练信息管理系统软件来发挥其高效地信息处理的作用,可以规范信息管理流程,让管理工作可以系统化和程序化,同时,球队训练信息管理系......