SingletonSystem 单例管理系统

news2024/12/23 15:03:51

SingletonSystem 单例管理系统

单例模式是项目中最为常见的设计模式之一,但是写法都不够优雅不方便查找和管理,下面介绍一种使用反射实现的单例管理架构,需要基于之前介绍过的AssemblyManager 程序集管理器

1.AssemblyManager

每次加载程序集的时候会有相应的事件回调机制,并且AssemblyManager 提供了遍历程序集中的类或者实现某个接口的类,使用此功能便能实现比较优雅的单例管理系统

2.定义两个接口ISingleton、IUpdateSingleton

public interface ISingleton : IDisposable
{
    public bool IsDisposed { get; set; }
    Task Initialize();
}
public interface IUpdateSingleton : ISingleton
{
    public void Update();
}

3.单例基类Singleton

public abstract class Singleton<T> : ISingleton where T : ISingleton, new()
{
    public bool IsDisposed { get; set; }
    public static T Instance { get; private set; }

    private void RegisterSingleton(ISingleton singleton)
    {
        Instance = (T)singleton;
        IsDisposed = false;
        AssemblyManager.OnLoadAssemblyEvent += Load;
        AssemblyManager.OnUnLoadAssemblyEvent += UnLoad;
    }

    protected abstract void UnLoad(int assemblyName);

    protected abstract void Load(int assemblyName);

    public virtual Task Initialize()
    {
        return Task.CompletedTask;
    }
    public virtual void Dispose()
    {
        IsDisposed = true;
        Instance = default;
        AssemblyManager.OnLoadAssemblyEvent -= Load;
        AssemblyManager.OnUnLoadAssemblyEvent -= UnLoad;
    }
}

4.SingletonSystem单例管理系统

首先用队列存储所有程序集中单例实现Update的接口,便于每帧更新
其次使用多值队列存储某个程序集中所有的单例

    private static readonly Queue<IUpdateSingleton> updateSingletons = new Queue<IUpdateSingleton>();
    private static readonly OneToManyQueue<int, ISingleton> singletons = new OneToManyQueue<int, ISingleton>();

初始化SingletonSystem,需要外界手动调用

    public static void Initialize()
    {
        AssemblyManager.OnLoadAssemblyEvent += Load;
        AssemblyManager.OnUnLoadAssemblyEvent += UnLoad;
    }

单例系统的释放,需要外界手动调用

    public static void Dispose()
    {
        foreach (var item in singletons.Values)
        {
            UnLoad(item);
        }
        updateSingletons.Clear();
        singletons.Clear();
        AssemblyManager.OnLoadAssemblyEvent -= Load;
        AssemblyManager.OnUnLoadAssemblyEvent -= UnLoad;
    }

其余加载卸载

    private static void UnLoad(int assemblyName)
    {
        if (!singletons.TryGetValue(assemblyName, out var queue))
            return;
        UnLoad(queue);
        singletons.RemoveKey(assemblyName);
    }

    private static void Load(int assemblyName)
    {
        List<Task> tasks = new List<Task>();
        UnLoad(assemblyName);

        foreach (Type singletonType in AssemblyManager.ForEach(assemblyName,typeof(ISingleton)))
        {
            var instance = (ISingleton)Activator.CreateInstance(singletonType);
            MethodInfo registerMethodInfo = singletonType.BaseType?.GetMethod("RegisterSingleton", BindingFlags.Instance | BindingFlags.NonPublic);
            MethodInfo initializeMethodInfo = singletonType.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.Public);
            MethodInfo onLoadMethodInfo = singletonType.GetMethod("Load", BindingFlags.Instance | BindingFlags.NonPublic);

            if (initializeMethodInfo != null)
            {
                tasks.Add((Task)initializeMethodInfo.Invoke(instance, null));
            }
            registerMethodInfo?.Invoke(instance, new object[] { instance });
            onLoadMethodInfo?.Invoke(instance, new object[] { assemblyName });

            switch (instance)
            {
                case IUpdateSingleton updateSingleton:
                    updateSingletons.Enqueue(updateSingleton);
                    break;
                default:
                    break;
            }
            singletons.Enqueue(assemblyName, instance);
        }

        Task.WaitAll(tasks.ToArray());
    }

    public static void Update()
    {
        int updateCount = updateSingletons.Count;
        while (updateCount-- >0)
        {
            IUpdateSingleton updateSingleton = updateSingletons.Dequeue();
            if (updateSingleton.IsDisposed)
                continue;
            updateSingletons.Enqueue(updateSingleton);
            try
            {
                updateSingleton.Update();
            }
            catch (Exception ex)
            {
                Debug.LogError(ex.Message);
            }
        }
    }

    private static void UnLoad(Queue<ISingleton> queue)
    {
        if (queue == null)
            return;
        while (queue.Count > 0)
        {
            try
            {
                queue.Dequeue().Dispose();
            }
            catch (Exception ex)
            {
                Debug.LogError(ex.Message);
            }
        }
    }

5.测试

测试单例

public class TestSingleton : Singleton<TestSingleton>,IUpdateSingleton
{
    public override Task Initialize()
    {
        Debug.Log("TestSingleton 初始化");
        return base.Initialize();
    }
    protected override void Load(int assemblyName)
    {
    }

    protected override void UnLoad(int assemblyName)
    {
        Debug.Log("卸载!");
    }

    public void TestFunc()
    {
        Debug.Log("调用单例测试方法!!!");
    }

    public void Update()
    {
        Debug.Log("单例Update方法!!!");
    }
}
public class Test : MonoBehaviour
{
    void Start()
    {
        SingletonSystem.Initialize();
        AssemblyManager.Initialize();

        TestSingleton.Instance.TestFunc();
    }


    private void Update()
    {
        SingletonSystem.Update();

        if (Input.GetKeyDown(KeyCode.P))
        {
            TestSingleton.Instance.TestFunc();
        }
    }
}

在这里插入图片描述

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

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

相关文章

Kubernetes技术--k8s核心技术 Secret

1.概述 Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret可以以 Volume 或者环境变量的方式使用。 作用 加密数据存储在/etc中,使得pod容器以挂载volume方式进行访问。在进行的数据存储中是以base64加密的方式…

Gromacs模拟体系构建----进阶版

Gromacs是目前广泛使用的分子模拟软件&#xff0c;其在生物、材料等领域的模拟表现出较为突出的优势。之前&#xff0c;本公众号介绍过一系列体系的模拟以及gromacs的使用办法和教程。本次&#xff0c;将为大家介绍一种进阶版的模型构建方法。 在之前的介绍中&#xff0c;我们…

Windows修改电脑DNS

访问浏览器出现无法访问此页面&#xff0c;找不到DNS地址&#xff0c;则可以通过如下方式修改DNS 按下windows键R键(两个键一起按) 出现下面窗口 输入control按回车键(Enter键)就会出现下面的窗口 DNS可以填下面这些&#xff1a; 114.114.114.114 和 114.114.115.115 阿里DNS&a…

Virtualenvwrapper 的安装教程

Virtualenvwrapper Virtaulenvwrapper是virtualenv的扩展包&#xff0c;用于更方便管理虚拟环境&#xff0c;它可以做&#xff1a; 将所有虚拟环境整合在一个目录下管理&#xff08;新增&#xff0c;删除&#xff0c;复制&#xff09;虚拟环境快速切换虚拟环境 安装方法 Li…

Java String类(2)

String方法 字符串拆分 可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串 相关方法如下&#xff1a; 方法功能String[ ] split(String regex)//以regex分割将字符串根据regex全部拆分String[ ] split(String regex, int limit)将字符串以指定的格式&#xff0c;拆…

浅谈为什么磁盘慢会导致Linux负载飙升

先说原因结论 在Linux系统上&#xff0c;load average这个指标基本失去了作用&#xff0c;因为你不知道它代表什么意思&#xff0c;当看到load average很高的时候&#xff0c;你不知道是runnable进程太多还是uninterruptible sleep进程太多&#xff0c;也就无法判断是CPU不够用…

bazel高效使用和调优

Bazel 为了正确性和高性能&#xff0c;做了很多优秀的设计&#xff0c;那么我们如何正确的使用这些能力&#xff0c;让我们的构建性能“起飞”呢&#xff0c; 我们将从本地研发和 CI pipeline 两种场景进行分析。 本地研发 本地研发通常采用默认的 Bazel 配置即可&#xff0c…

C# Solidworks二次开发:创建距离配合以及移动组件API详解

今天要讲的文章是关于如何创建距离配合和移动组件的API详解。 &#xff08;1&#xff09;创建配合API&#xff0c;CreateMate() 这个API的解释是根据指定的特性数据对象来创建配合&#xff0c;也就可以理解为输入什么样的特征对象就可以创建出什么配合&#xff0c;这个API的输…

YOLOv5算法改进(12)— 替换主干网络之Swin Transformer

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。Swin Transformer是一种基于Transformer的深度学习模型&#xff0c;它在视觉任务中表现出色。与之前的Vision Transformer&#xff08;ViT&#xff09;不同&#xff0c;Swin Transformer具有高效和精确的特性&#xff0c;并…

学用 CountDownLatch 与 CyclicBarrier

开篇即说结论&#xff0c;如果搞不清楚两者区别&#xff0c;那就无脑用 CountDownLatch&#xff0c;问题也不大&#xff08;因为我也不是太懂&#xff09;。 CountDownLatch 模拟了100米赛跑&#xff0c;10名选手已经准备就绪&#xff0c;只等裁判一声令下。当所有人都到达终…

R3LIVE源码解析(7) — R3LIVE中LiDAR_front_end.cpp文件

目录 1 LiDAR_front_end.cpp简介 2 LiDAR_front_end.cpp程序解析 1 LiDAR_front_end.cpp简介 激光点云首先在LiDAR_front_end节点中提取特征点&#xff0c;将处理完的信息通过/laser_cloud_flat完成节点的发送出去&#xff0c;与FAST-LIO2相同R3LIVE也只用到了面特征作为ESI…

在windows上配置ninja环境

ninja使用并行任务来编译工程&#xff0c;比cmake编译快了一个数量级&#xff0c;是谷歌在2010年为了提高cmake的编译速度而开发一款编译工具。下面介绍在windows上配置ninja环境。 1 下载ninja ninja官网地址&#xff1a; https://github.com/ninja-build/ninja/releases   …

【OpenCV入门】第七部分——图像的几何变换

文章结构 缩放dsize参数实现缩放fx参数和fy参数实现缩放 翻转仿射变换平移旋转倾斜 透视cmath模块 缩放 通过resize()方法可以随意更改图像的大小比例&#xff1a; dst cv2.resize(src, dsize, fx, fy, interpolation)src&#xff1a; 原始图像dsize&#xff1a; 输出图像的…

Leetcode---360周赛

题目列表 2833. 距离原点最远的点 2834. 找出美丽数组的最小和 2835. 使子序列的和等于目标的最少操作次数 2836. 在传球游戏中最大化函数值 一、距离原点最远的点 这题主要是理解题意&#xff0c;遇到L往左走&#xff0c;遇到R往右走&#xff0c;遇到_左右都可以走&#x…

bazel外部依赖管理

前面我们主要分析了基于 Action 的增量构建&#xff0c;缓存和远程执行机制。现在让我们看看 Bazel 是如何管理外部依赖的。 大部分项目都没法避免引入第三方的依赖项。构建系统通常提供了下载第三方依赖的能力。为了避免重复下载&#xff0c;Bazel 要求在声明外部依赖的时候&…

美客多(mercadolibre)测评下单技术(养号环境搭建详解)

MercadoLibre&#xff08;美客多&#xff09;是拉丁美洲的一个网购平台。该公司为其客户提供电子商务交易的购买&#xff0c;出售&#xff0c;支付和收集机制。目前全球第十大电商市场——巴西是MercadoLibre的主要市场&#xff0c;占据近60%的平台营收&#xff0c;接着是阿根廷…

关于购买AirPods,现在是否为最佳时机?

我们不需要解释你为什么想要AirPods。苹果对真正的无线耳机的采用彻底改变了市场&#xff0c;并从那时起大量销售。你总是在记者、同事和名人的耳朵里看到它们——尤其是在我们这个远程工作和Zoom会议的时代。 真正的问题是&#xff0c;你应该现在就买一个&#xff0c;还是在几…

2024年java面试--多线程(1)

系列文章目录 2024年java面试&#xff08;一&#xff09;–spring篇2024年java面试&#xff08;二&#xff09;–spring篇2024年java面试&#xff08;三&#xff09;–spring篇2024年java面试&#xff08;四&#xff09;–spring篇 文章目录 系列文章目录线程调度线程五种状态…

spring boot项目生成容器并运行

一个安静的周末&#xff0c;shigen又睡懒觉了&#xff0c;上次说的拖延症的惩罚来了&#xff1a;早晚各100个健腹轮练习&#xff0c;早上的已经完成了。今天的文章来的有点晚&#xff0c;但是依旧保持质量。 springboot项目生成容器并运行 背景 将springboot项目打包成jar包&…

2021年03月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;生日相同 2.0 在一个有180人的大班级中&#xff0c;存在两个人生日相同的概率非常大&#xff0c;现给出每个学生的名字&#xff0c;出生月日。试找出所有生日相同的学生。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 第一行为整数n&#xff0c…