• SingletonKit单例源码阅读学习


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

    image-20240617170633493

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

    image-20240617175832663

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

    img

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

    image-20240617184607191

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

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

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

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

    image-20240617185704194

    image-20240617185718773

    UML图

    image-20240617201339124

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

本文作者:畅知

本文链接:https://www.cnblogs.com/tonycode/p/18253139

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

  • 相关阅读:
    学生HTML个人网页作业作品——湘菜美食网页设计作品(12页) 美食网站设计与实现
    thinkphp5.0.23漏洞复现以及脚本编写
    JS模块化
    元素显示模式转换
    软件工程-第7章 面向对象方法基础
    Linux 基础-文件权限与属性
    自制OS1-1到2-11==BIOS MBR loader
    centos 里面的service自启动app.jar,出现两个java进程,app是同一个端口
    CSS进阶
    whisper 语音识别项目部署
  • 原文地址:https://www.cnblogs.com/TonyCode/p/18253139