首页 > 其他分享 >技术笔记(1)QFramework

技术笔记(1)QFramework

时间:2024-03-06 19:56:22浏览次数:20  
标签:Event QFramework 笔记 技术 static 单例 Command public 构造函数

技术笔记(1)QFramework

  • 希望实现的功能或目标:

    • 了解学习游戏开发中的架构演化过程
    • 了解学习IOC容器、DI等相关概念

  • 学习笔记:

    • BindableProperty类

      • 实际上是数据+事件
      • 我理解为将模型层中的一个数据整合升级成一个类,并将修改和获取其的具体方法放在属性的get和set方法中
      • 比如killCount每次被修改时,在它的set方法中顺带调用一个事件去修改表现层
    • ICommand接口

      • 实现了Execute()方法

      • 实现了该接口的实例被调用的形式举例:

        new KillEnemyCommand
        	.Execute();
        
      • 可被表现层用以修改模型层的数据

    • 底层系统层的元素

      • Command
      • Event
      • Model
    • 架构使用原则

      • 事件(Event)由系统层向表现层发送
      • 表现层只能用Command改变底层系统层的状态和数据
      • 表现层可以直接查询数据
    • 单例工具类 Singleton

      • 实现如下:

        public calss Singleton<T> where T :Singleton<T>
        {
        	private static T mInstance;
        	public static T Instance
        	{
        		get
        		{
        			if(mInstance == null)
        			{
        				var type = typeof(T);
        				var ctors = type.GerConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
        				var ctor = Array.Find(ctors,c => c.GetParameters().Length == 0);
        
        				if(ctor == null)
        				{
        					throw new Exception("Non Public Constructor Not Found in" + type.Name);
        				}
        
        				mInstance = ctor.Inboke(null) as T;
        			}
        				return mInstance;
        		}
        	}
        }
        
    • IOC容器

      • 其逻辑为:简单理解为一个字典,这个字典以类型为Key,Object为Value

      • 最少有两个核心API,根据Type注册实例,根据Type获取实例

      • 具体实现:

        • public class IOCContainer
          {
          	private Dictionary<Type, object> mInstances = new Dictionary<Type, object>();
          
          	public void Register<T>(T instance)
          	{
          		var key = typeof(T);
          		if(mInstances.ContainsKey(key))
          		{
          			mInstances[key] = instance;
          		}
          		else
          		{
          			mInstances.Add(key, instance);
          		}
          	}
          
          	public T Get<T>() where T : class
          	{
          		var key = typeof(T);
          
          		if(mInstances.TryGetValue(key, out var retInstance))
          		{
          			return retInstance as T;
          		}
          
          		return null;
          	}
          }
          
    • 模块化

      • 表现层模块化:直接使用平台提供的概念即可,比如Scene或Prefab

      • 底层系统层模块化:需要考虑模块对象如何获取?如何增加一个模块?

      • 当前在底层系统层已经模块化的为模型层,如下:

        • public static class CounterModel
          {
          	public static BindableProperty<int> Count = new BindableProperty<int>(){
          		Value = 0;
          	};
          }
          
      • 此处展示的CounterModel为一个静态类,其优势为:

        • 静态类可以直接获取
        • 扩展一个静态类只需要加上一个static
      • 相应的,其缺点为:

        • 静态类没有访问限制,会留下隐患
        • 模块识别度不高,无法分清其到底是模块还是工具类还是常量类
      • 解决方式:

        • 一种方法是将其设置为单例类,必须通过 模块类.Instance 获取,增加模块获取难度。继承单例工具类,并取消静态后,模型层变为:

          • public class CounterModel :Singleton<CounterModel>
            {
            	public CounterModel() {} //补上一个无参构造函数
            
            	public BindableProperty<int> Count = new BindableProperty<int>(){
            		Value = 0;
            	};
            }
            
        • 另一种方法是不用单例,把CounterModel注册进IOC容器之中,通过 CountApp.Get<CounterModel>() 获取:

          • public class CounterApp
            {
            	private static IOCContainer mContainer;
            
            	static void MakeSureContainer()
            	{
            		if(mContainer == null) 
            		{
            			mContainer = new IOCContainer();
            			Init();
            		}
            	}
            
            	static void Init()
            	{
            		mContainer.Register(new CounterModel());
            	}
            
            	public static T Get<T>() where T : class
            	{
            		MakeSureContainer();
            		return mContainer.Get<T>();
            	}
            
            }
            

  • 产生的疑惑:

    • Command、Event初次接触,还有点模糊不清

    • 面向组件编程?ESC架构?

    • 单例类中所涉及的反射的相关概念?

    • 要用单例模式的话不是直接在类内设置一个公开静态变量引用自身就行吗?为什么还要去弄个单例工具类?其好处和优点是什么?

    • 单例类没有访问限制这一点会引发什么风险?

    • 引入单例类和IOC之后还是只看到了变复杂的流程和结构,暂时没看到其带来的好处。

    • IOC容器里只装模块类吗?还是能装哪些类?

  • 思考和解惑:

    • 关于QFramework里的Command和Event:

      • 定义:

        • Command指客户端发起的改变服务器端状态的请求,比如:增加计数、减少计数等;

        • Event指服务器端发布的已经发生的状态变化,比如计数增加事件、计数减少事件等。

      • 好处:

        • 降低Controller的复杂度,交互逻辑分离到Command中,表现逻辑分离到Event中,使Controller更加简洁和清晰;
        • 提高可扩展性和可维护性,增减功能只需要注册和删改Command和Event,不需要修改其余代码
      • 对比与区别:

        • Command是主动的行为,需要有一个明确的接受者来执行;而Event是一种被动的行为,不关心有没有监听者来响应。
        • Command有返回值,返回成功或失败的结果;而Event无返回值,只负责通知发生甚么事了,不需要等待任何反馈
    • 面向组件编程:将程序看作是由一系列可重用的组件组成的,这些组件通过组合和配置来构建应用程序。Unity就属于一个典型例子。

    • ESC架构:将游戏对象分为实体Entity、逐渐Component和系统System三个部分,其中:

      • 实体是游戏对象的容器,它没有任何行为或属性,只是一个标识符。
      • 组件是游戏系统对象的属性活性位,例如位置、速度、生命值等。
      • 系统是游戏对象的行为逻辑,例如移动、攻击、碰撞检测等。
    • 反射:作为一种机制,运行程序在运行时动态地获取和操作类的信息,比如类的名称、属性、方法、构造函数等。通过反射可以访问和修改类的私有成员,包括私有的构造函数。

      • 在上述泛型单例类中,用到反射概念的语句主要有以下几个:

        • var type = typeof(T); //获取泛型类型T的类型信息
        • var ctors = type.GetConstructors(BindingFlags.Instance|BindingFlags.NonPublic); //获取T类型的所有非公共的实力构造函数
        • var ctor = Array.Find(ctors, c=>c.GetParameters().Length==0); //从ctors数组中查找一个没有参数的构造函数
        • mInstance = ctor.Invoke(null) as T; //传入null参数,调用T类型的非公共无参构造函数,创造一个T类型的实例
    • 对于这种简单的单例模式:

      public class MyClass myclass : monobehavior
      {
           public static MyClass instance;
      
           private void awake()
           {
               instance = this;
           }
      
      }
      
      • 其存在的问题是:

        • 该单例类必须继承自MonoBehaviour,这意味着它必须挂载到一个场景中的游戏对象上,而不能作为一个普通的C#类
        • 其实例化依赖于Awake方法的调用顺序,如果有其他脚本在Awake方法中调用该单例类,可能会出现空引用的异常
        • 该单例类没有保证线程安全,如果有多个线程同时访问,可能会出现静态条件
      • 相比之下,用泛型单例工具类来实现单例模式的话,有以下优势:

        • 不必继承自MonoBehaviour
        • 保证实例创建时机,保证线程安全
        • 使用私有的无参构造函数,防止外部创建,也防止反射破坏单例类特性
    • 单例类没有访问限制的风险:

      • 破坏唯一性,如果没有将构造函数设为私有,那么外部可以new出很多个单例类的实例
      • 多线程不安全,可能出现多个线程同时创建或访问单例类的实例
    • 好处:

      • 单例类可以保证一个类只有一个实例,从而节省内存,提高访问速度,控制资源的使用,方便数据的共享等。适用于那些需要全局唯一的对象,如配置文件、日志对象、数据库连接池等。
      • IOC可以降低类之间的耦合,提高类的可复用性和可维护性,实现控制反转和依赖注入,方便测试和扩展等。适用于那些需要灵活配置和组合的对象,如业务逻辑层、数据访问层、控制器层等。
    • 目前已知可以装模型层、系统层和工具层的类

日期:3.4

标签:Event,QFramework,笔记,技术,static,单例,Command,public,构造函数
From: https://www.cnblogs.com/bqza000/p/18057409

相关文章

  • 技术笔记(3)扩展方法
    技术笔记(3)扩展方法希望实现的功能或目标:继续学习MMORPG游戏开发的框架了解扩展方法‍学习笔记:CanGetLayersExtension类扩展方法GetSystem:publicstaticTGetSystem<T>(thisICanGetSystemself)whereT:class,ISystem{returnStartArchitecture.I......
  • 技术笔记(2)MMORPG架构
    技术笔记(2)MMORPG架构希望实现的功能或目标:一个功能完整的接近商业案例的MMORPG游戏项目搭建起该游戏项目的基本架构‍学习笔记:IOCContainer类用以保存所有层级以及各个模块的实例实例字典​privateDictionary<Type,object>instancesDict=newDictiona......
  • XXL-JOB 使用笔记(附代码)
    一:分布式调度系统对比开源产品对比:Quartz缺点: 1、不支持任务编排,无可视化编配页面 2、与业务高度耦合,系统侵入性严重 3.调度逻辑和QuartzJobBean耦合在同一个项目中,任务增加会导致系统性能瓶颈 4.quartz底层以“抢占式”获取DB锁并由抢占成功节点负责运行任务,会导......
  • 线性代数——平面向量 学习笔记
    线性代数——平面向量学习笔记首发于洛谷。定义及用语说明无特殊说明,下文的向量均指自由向量且是平面向量。向量,英文名为vector,目前没有准确而统一的中文翻译。在物理学科,一般翻译成「矢量」,且与「标量」一词相对。在数学学科,一般直接翻译成「向量」。对于向量的乘法:......
  • Vue学习笔记3--组件嵌套
    组件嵌套示例一:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>非单文件组件--全局注册</tit......
  • NGUI学习笔记4.0
    EventListener和EventTrigger控件自带组件的局限性其实我们常见的复合控件只提供一些简单的事件监听,如按钮有点击抬起的监听,对长按等其他交互方式的事件监听不大支持。NGUI的监听函数给NGUI对象添加Collider,在其挂载的脚本中编写对应的NGUI的函数,在运行时候会通过反射来进行匹......
  • Mybatis学习笔记
    Mybatis代码Mybatis入门https://mybatis.net.cn/getting-started.html写一个Mybatis项目1、新建一个Maven项目2、导入依赖集<!--导入依赖--><dependencies><!--mysql驱动--><dependency><groupId>mysql</groupId>......
  • pandas笔记(二)-- 从不订购的顾客 (数据表连接,主键与外键)
    题目描述找出所有从不点任何东西的顾客,以任意顺序返回结果测试用例输入Customerstable:idname1Joe2Henry3Sam4MaxOrderstable:idcustomerId1321输出CustomersHenryMax解析数据表连接的问题核心在于连接......
  • 数位DP 学习笔记
    什么是数位DP数位dp是与数字相关的一类计数问题。这这类问题中,一般给定一些限制条件,求满足第\(K\)小的数是多少,或者求区间\([L,R]\)内有多少个满足条件的数。本文主要讲述如何解决求区间\([L,R]\)内有多少个满足条件的数这一类问题。为什么要用数位dp对于上述问题,如果......
  • 来了哪些领军人物?2024数据技术嘉年华主论坛揭晓!
    在1978年,中国人民大学经济信息管理系首任系主任萨师煊,第一次将“数据库”这三个字写在黑板上。这个看似平凡的举动,却点燃了中国数据库行业的火花。时光流转,如今我们站在了数字化时代的前沿。回顾过去,数据库技术的发展历程就像是一幅壮丽的画卷,从最初的穿孔纸带和文件系统,到层次模......