App Instance 架构示例

news2024/11/15 10:28:14
前言

        在Unity程序设计过程中,我们处理的第一个对象是Application Instance。

        它的主要职责是启动流程管理、卸载流程管理,次要职责是管理在内部的子系统生命周期。其他职责,提供或桥接应用程序的配置信息、及其他第三方接口。

        它通常以单例的形式存在在场景中,即使在切换场景时,也不会被删除。

设计需求        
  1. 可以自定义异步启动流程、或卸载流程
  2. App 自动完成子系统的初始化和卸载工作
  3. 子系统是可轻松扩展的
  4. 通过App Instance可以轻松访问到子系统实例
UML结构
UML类结构示例
代码示例
//> XApplication.Utils.cs
//> Create by UniMark

namespace XF 
{
    public interface IApplication 
    {
        void Startup();
        void Initialize();
        void Deinitialize();
        void Shutdown();
    }

    public interface IApplicationSubSystem 
    {
        int InitializeSequence { get; }
        void Initialize(XApplication application);
        void Deinitialize();
    }
}
//> XApplication.cs
//> Create by UniMark

using System;
using System.Collections.Generic;
using UnityEngine;

namespace XF
{
    public sealed class XApplication : MonoBehaviour
    {
        private IApplication Application;
        private IApplicationSubSystem[] ApplicationSubSystems = new IApplicationSubSystem[0];
        private Dictionary<Type, IApplicationSubSystem> QuickReferenceTable;

        private void Awake ()
        {
            Debug.Log($"启动 [XApplication] 实例 ({gameObject.name})");
            if ( ( Application = GetComponent<IApplication>() ) == null )
            {
                throw new Exception("你需要实现IApplication的接口");
            }

            ApplicationSubSystems = GetAllApplicationSubSystemWithSequence();
            QuickReferenceTable = GetQuickReferenceTableWithAppSubSystem(ApplicationSubSystems);
            Application.Startup();
        }

        private void Start ()
        {
            if ( ApplicationSubSystems.Length > 0 )
            {
                Debug.Log("实例化应用内联系统 ...");
                for ( int index = 0; index < ApplicationSubSystems.Length; index++ )
                {
                    var subSystem = ApplicationSubSystems[index];
                    var time = Time.time;
                    subSystem.Initialize(this);
                    Debug.Log($"释放: {subSystem.GetType().Name} 耗时 {( Time.time - time ).ToString("{0.000}")}s");
                }
            }

            if ( Application != null )
            {
                Debug.Log("实例化应用 ...");
                Application?.Initialize();
            }
        }

        private void OnDestroy ()
        {
            if ( Application != null )
            {
                Debug.Log("释放应用 ...");
                Application?.Deinitialize();
            }

            if ( ApplicationSubSystems.Length > 0 )
            {
                Debug.Log("释放应用内联系统 ..."); 
                for ( int index = ApplicationSubSystems.Length - 1; index >= 0; index-- )
                {
                    var subSystem = ApplicationSubSystems[index];
                    var time = Time.time;
                    subSystem.Deinitialize();
                    Debug.Log($"释放: {subSystem.GetType().Name} 耗时 {(Time.time - time).ToString("{0.000}")}s");
                }
            }

            Debug.Log($"关闭 [XApplication] 实例 ({gameObject.name})");
            Application.Shutdown();
            Application = null;
            ApplicationSubSystems = null;
            QuickReferenceTable = null;
        }

        private IApplicationSubSystem[] GetAllApplicationSubSystemWithSequence ()
        {
            var list = new List<IApplicationSubSystem>();
            GetComponentsInChildren(true, list);
            list.Sort(( a, b ) => a.InitializeSequence.CompareTo(b.InitializeSequence));
            return list.ToArray();
        }

        private Dictionary<Type, IApplicationSubSystem> GetQuickReferenceTableWithAppSubSystem ( IApplicationSubSystem[] systems )
        {
            Dictionary<Type, IApplicationSubSystem> result = new Dictionary<Type, IApplicationSubSystem>();
            foreach ( var system in systems )
            {
                if ( false == result.TryAdd(system.GetType(), system) )
                {
                    throw new Exception($"包含相同类型的子系统 {system.GetType().Name}");
                }
            }
            return result;
        }

        #region API
        public T GetSubSystem<T> () where T : MonoBehaviour, IApplicationSubSystem
        {
            if ( QuickReferenceTable.TryGetValue(typeof(T), out var system) )
            {
                return system as T;
            }

            throw new Exception($"不存在的子系统 {typeof(T).Name}");
        }
        #endregion
    }
}
//> XGame.cs
//> Create by UniMark

using System;
using UnityEngine;
using XF;

public abstract class XGame<T> : MonoBehaviour, IApplication
    where T : XGame<T>
{
    public static T Instance
    {
        get; private set;
    }
    public XApplication Owner
    {
        get; private set;
    }

    //> 定义你自己的系统在这里    
     public TestSubSystem TestSystem { get; private set; }

    void IApplication.Startup ()
    {
        if ( Instance != null )
        {
            throw new Exception($"[{gameObject.name}]{this.GetType().Name}类存在多实例异常!");
        }

        Instance = this as T;
        GameObject.DontDestroyOnLoad(gameObject);
        Owner = GetComponent<XApplication>();

        //> 初始化你的系统在这里
        TestSystem = Owner.GetSubSystem<TestSubSystem>();
    }

    void IApplication.Shutdown ()
    {
        Instance = null;
        Owner = null;

        //> 释放你的系统在这里
        TestSystem = null;
    }

    void IApplication.Initialize () => StartGame();
    void IApplication.Deinitialize () => QuitGame();

    protected abstract void StartGame ();
    protected abstract void QuitGame ();
}
//> GameIns.cs
//> Create by UniMark

using UnityEngine;
using XF;


public class GameIns : XGame<GameIns>
{

    #region 生命周期
    protected override async void StartGame ()
    {
        //> 加载配置文件 
        //> await 配置文件加载完毕

        //> 做个测试
        var testSystem =  Owner.GetSubSystem<TestSubSystem> ();
        Debug.Log(testSystem.GetMessage());

        //> 进入第一个场景
    }


    protected override void QuitGame ()
    {
        //> 在这里卸载业务载入的资源和数据
    }
    #endregion
}
//> TestSubSystem.cs
//> Create by UniMark


using UnityEngine;

namespace XF
{
    #region 非正式代码
    public class TestSubSystem : MonoBehaviour, IApplicationSubSystem
    {
        [SerializeField]
        private int InitializeSequence;

        int IApplicationSubSystem.InitializeSequence => InitializeSequence;

        private XApplication Owner;

        void IApplicationSubSystem.Initialize ( XApplication application )
        {
            Owner = application;
        }

        void IApplicationSubSystem.Deinitialize ()
        {
            Owner = null;
        }

        public string GetMessage ()
        {
            return "Hello Here!";
        }
    }
    #endregion
}
代码组织结构

-| Scripts

        --| Core

                ---| SubSystems

                        ---- TestSubSystem.cs

                --- XApplication.cs

                --- XApplication.Utils.cs

                --- XGame.cs

        -- GameIns.cs

创建应用程序预制体
预制体组织结构
XApplication 节点
TestSubSystem 节点
下载代码示例 

 下载demo

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

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

相关文章

buu做题(7)

[BJDCTF2020]Mark loves cat 开始的界面没啥东西, 看了下源码好像也没啥东西 用dirsearch扫描一下 有git 泄露 用工具githack下载源码 <?phpinclude flag.php;$yds "dog"; $is "cat"; $handsome yds;foreach($_POST as $x > $y){$$x $y; }f…

【过题记录】 7.21

Mad MAD Sum 算法&#xff1a;思维&#xff0c;前缀最大值 模拟一下他的运行过程就会发现&#xff0c;两次之后整个数组就固定了&#xff0c;之后每次都是每个数往后移动一位&#xff0c;可以模拟两次之后计算每个数的存活轮数&#xff0c;计算贡献。 #include<bits/stdc.h…

FreeRTOS 任务的挂起与恢复

任务的挂起与恢复的API函数 挂起 - vTaskSuspend 挂起任务类似暂停&#xff0c;可恢复&#xff1b; 删除任务&#xff0c;无法恢复&#xff0c;类似“人死两清” 使用 必须将 INCLUDE_vTaskSuspend 定义为 1 才能使用此函数 void vTaskSuspend( TaskHandle_t xTaskToSuspen…

GIT命令学习 二

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…

PostgreSQL简介和安装

一、Postgresql简介&#xff1a; 1、PostgreSql是功能强大的&#xff0c;开源的关系型数据库&#xff0c;底层基于C语言实现&#xff1b; 2、开源&#xff1a;允许对PostgreSql进行封装&#xff0c;用于商业收费&#xff1b; 3、版本迭代速度快&#xff0c;正式版本已经到15.R…

《昇思25天学习打卡营第24天|基于 MindSpore 实现 BERT 对话情绪识别》

1. BERT 模型概述 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是一个预训练的语言表示模型&#xff0c;可以应用于多种自然语言处理任务&#xff0c;包括对话情绪识别。BERT 通过双向 Transformer 编码器&#xff0c;能同时考虑句子…

【Langchain大语言模型开发教程】基于文档问答

&#x1f517; LangChain for LLM Application Development - DeepLearning.AI Embedding&#xff1a; https://huggingface.co/BAAI/bge-large-en-v1.5/tree/main 学习目标 1、Embedding and Vector Store 2、RetrievalQA 引包、加载环境变量 import osfrom dotenv import…

单例模式_Golang

目录 一、单例模式 1.1 基本概念 1.2 使用场景 二、Golang实现 2.1 懒汉模式&#xff08;Lazy Loading&#xff09; 一、单例模式 1.1 基本概念 一个类只能生成一个实例&#xff0c;且该类能自行创建这个实例的一种模式,这个定义个人感觉可以拆的通俗一些,在项目的生命周…

2-41 基于matlab的小车倒立摆系统的控制及GUI动画演示

基于matlab的小车倒立摆系统的控制及GUI动画演示。输入小车及倒立摆的初始参数&#xff0c;位置参数&#xff0c;对仿真时间和步长进行设置&#xff0c;通过LQR计算K值&#xff0c;进行角度、角速度、位置、速度仿真及曲线输出&#xff0c;程序已调通&#xff0c;可直接运行。 …

【BUG】已解决:ModuleNotFoundError: No module named‘ pip‘

已解决&#xff1a;ModuleNotFoundError: No module named‘ pip‘ 目录 已解决&#xff1a;ModuleNotFoundError: No module named‘ pip‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰…

JAVA零基础学习2(算术逻辑三元运算符、原码反码补码、标准的类如何描写)

JAVA零基础学习2&#xff08;算术逻辑三元运算符、原码反码补码、标准的类如何描写&#xff09; 算术运算符算术运算符自增和自减运算符算术运算符的优先级示例代码 逻辑运算符三元运算符示例代码示例1&#xff1a;简单的条件判断示例2&#xff1a;嵌套的三元运算符 原码反码补…

WebGSI地图切片|栅格地图切片原理|地图矢量切片原理

介绍 图栅格切片是WebGIS中使用的一种新技术&#xff0c;通过地图栅格切片可以有效缩短服务器的地图生成时间和地图传输时间&#xff0c;提高系统的响应速度。 地图切片是在多个比例尺下配置地图&#xff0c;预先将每个比例尺下的地图绘制成小图片&#xff0c;保存到服务器上一…

set(集合),multiset容器及pair队组的创建

1.set的基本概念&#xff1a;所有元素再插入时自动按升序排序&#xff0c;set/multiset属于关联式容器&#xff0c;底层结构是用二叉树实现的 set与multiset区别&#xff1a; set中不允许容器中有重复的元素 multiset允许容器中有重复的元素 2.set的构造函数 3.set的大小和…

【Linux】进程间通信之-- 共享内存与信号量的介绍(下)

前言 上一篇&#xff0c;我们由进程间通信&#xff0c;引入并讲述了管道、匿名管道和命名管道&#xff0c;本节&#xff0c;将继续学习进程间通信的另一种方式之&#xff0c;共享内存。还要学习几个系统调用接口&#xff0c;并演示两个进程通过共享内存来进行通信。。。 目录 1…

数据结构——队列(链式结构)

一、队列链式结构定义 队列的链式存储结构是一种用链表实现的队列,它不像顺序存储结构那样需要预先分配固定大小的空间。链式存储结构的队列由节点组成,每个节点包括数据和指向下一个节点的指针。队列的链式存储结构可以动态地分配内存,更灵活地处理数据。在链式存储结构中…

【07】LLaMA-Factory微调大模型——微调模型导出与微调参数分析

上文介绍了如何对微调后的模型进行使用与简单评估。本文将介绍对微调后的模型进行导出的过程。 一、llama-3微调后的模型导出 首先进入虚拟环境&#xff0c;打开LLaMA-Factory的webui页面 conda activate GLM cd LLaMA-Factory llamafactory-cli webui 之后&#xff0c;选择…

SQL39道常见题型

SQL1 查询所有列 现在运营想要查看用户信息表中所有的数据&#xff0c;请你取出相应结果。 select * from user_profile 结果&#xff1a; SQL2 查询多列 还是上面那个输入&#xff0c;题目换成&#xff1a;现在运营同学想要用户的设备id对应的性别、年龄和学校的数据&#…

TIM基本定时器

TIM基本定时器 文章目录 TIM基本定时器1.定时器的分类2.定时器运行流程3.基本定时器的配置流程4.中断配置 1.定时器的分类 以STM32F1系列为例&#xff0c;它的定时器可以根据其特性和功能被分为三大类&#xff1a; 基本定时器&#xff1a; 包括&#xff1a;TIM6和TIM7。特点&a…

数据结构全部知识-----第一 关于数据结构的介绍

数据结构是计算机存储、组织数据的方式。它是计算机科学中的一个重要概念&#xff0c;主要目的是使数据的存储和访问更高效、更方便。常见的数据结构包括&#xff1a; 线性结构&#xff1a; 1. **数组&#xff08;Array&#xff09;** &#xff1a;一种基础的数据结构&#xf…

【BUG】已解决:AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘

AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘ 目录 AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘ 【常见模块错误】 【错误原因】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&…