• 【Unity 框架】QFramework v1.0 使用指南 架构篇:07. 使用 BindableProperty 优化事件 | Unity 游戏框架 | Unity 游戏开发 | Unity 独立游戏


    在这篇我们介绍一个新的概念 BindableProperty。

    BindableProperty 是包含 数据 + 数据变更事件 的一个对象。

    BindableProperty 基本使用

    简单的用法如下:

    var age = new BindableProperty<int>(10);
    
    age.Register(newAge=>{
      
      Debug.Log(newAge)
    }).UnRegisterWhenGameObjectDestoryed(gameObject);
    
    
    age++;
    age--;
    
    
    // 输出结果
    // 11
    // 10
    

    非常简单,就是当调用 age++ 和 age-- 的时候,就会触发数据变更事件。

    BindableProperty 除了提供 Register 这个 API 之外,还提供了 RegisterWithInitValue API,意思是 注册时 先把当前值返回过来。

    具体用法如下:

    var age = new BindableProperty<int>(5);
    
    age.RegisterWithInitValue(newAge => {
      
      Debug.Log(newAge);
      
    });
    
    // 输出结果
    // 5
    

    这个 API 就是,没有任何变化的情况下,age 先返回一个当前的值,比较方便用于显示初始界面。

    BindableProperty 是一个独立的工具,可以脱离 QFramework 架构使用,也就是说不用非要用 QFramework 的 MVC 才能用 BindableProperty,而是可以再自己项目中随意使用。

    使用 BindableProperty 优化 CounterApp 的代码

    我们直接优化即可,优化后代码如下:

    using UnityEngine;
    using UnityEngine.UI;
    
    namespace QFramework.Example
    {
        
        // 1. 定义一个 Model 对象
        public class CounterAppModel : AbstractModel
        {
            public BindableProperty<int> Count { get; } = new BindableProperty<int>();
    
            protected override void OnInit()
            {
                var storage = this.GetUtility<Storage>();
                
                // 设置初始值(不触发事件)
                Count.SetValueWithoutEvent(storage.LoadInt(nameof(Count)));
    
                // 当数据变更时 存储数据
                Count.Register(newCount =>
                {
                    storage.SaveInt(nameof(Count),newCount);
                });
            }
        }
    
    
        public class AchievementSystem : AbstractSystem 
        {
            protected override void OnInit()
            {
                this.GetModel<CounterAppModel>() // -+
                    .Count
                    .Register(newCount =>
                    {
                        if (newCount == 10)
                        {
                            Debug.Log("触发 点击达人 成就");
                        }
                        else if (newCount == 20)
                        {
                            Debug.Log("触发 点击专家 成就");
                        }
                        else if (newCount == -10)
                        {
                            Debug.Log("触发 点击菜鸟 成就");
                        }
                    });
            }
        }
    
        // 定义 utility 层
        public class Storage : IUtility
        {
            public void SaveInt(string key, int value)
            {
                PlayerPrefs.SetInt(key,value);
            }
    
            public int LoadInt(string key, int defaultValue = 0)
            {
                return PlayerPrefs.GetInt(key, defaultValue);
            }
        }
    
    
        // 2.定义一个架构(提供 MVC、分层、模块管理等)
        public class CounterApp : Architecture<CounterApp>
        {
            protected override void Init()
            {
                // 注册 System 
                this.RegisterSystem(new AchievementSystem()); // +
                 
                // 注册 Model
                this.RegisterModel(new CounterAppModel());
                
                // 注册存储工具的对象
                this.RegisterUtility(new Storage());
            }
        }
    
        // 引入 Command
        public class IncreaseCountCommand : AbstractCommand 
        {
            protected override void OnExecute()
            {
                var model = this.GetModel<CounterAppModel>();
                    
                model.Count.Value++; // -+
            }
        }
        
        public class DecreaseCountCommand : AbstractCommand
        {
            protected override void OnExecute()
            {
                this.GetModel<CounterAppModel>().Count.Value--; // -+
            }
        }
    
        // Controller
        public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
        {
            // View
            private Button mBtnAdd;
            private Button mBtnSub;
            private Text mCountText;
            
            // 4. Model
            private CounterAppModel mModel;
    
            void Start()
            {
                // 5. 获取模型
                mModel = this.GetModel<CounterAppModel>();
                
                // View 组件获取
                mBtnAdd = transform.Find("BtnAdd").GetComponent<Button>();
                mBtnSub = transform.Find("BtnSub").GetComponent<Button>();
                mCountText = transform.Find("CountText").GetComponent<Text>();
                
                
                // 监听输入
                mBtnAdd.onClick.AddListener(() =>
                {
                    // 交互逻辑
                    this.SendCommand<IncreaseCountCommand>();
                });
                
                mBtnSub.onClick.AddListener(() =>
                {
                    // 交互逻辑
                    this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
                });
    
                // 表现逻辑
                mModel.Count.RegisterWithInitValue(newCount => // -+
                {
                    UpdateView();
    
                }).UnRegisterWhenGameObjectDestroyed(gameObject);
            }
            
            void UpdateView()
            {
                mCountText.text = mModel.Count.ToString();
            }
    
            // 3.
            public IArchitecture GetArchitecture()
            {
                return CounterApp.Interface;
            }
    
            private void OnDestroy()
            {
                // 8. 将 Model 设置为空
                mModel = null;
            }
        }
    }
    
    

    代码改动很多,重要的改动为:

    • Model 中的 Count 和 mCount 改成了一个叫做 Count 的 BindableProperty
    • 删掉了 CountChangeEvent 改用监听 BindableProperty
    • Controller 在初始化中去掉一次 UpdateView 的主动调用

    可以说代码量一下子少了很多。

    我们看下运行结果:

    282fcc3c-96fa-46e1-b4c6-7f4528b04271.gif

    运行没问题。

    由于我们的 Count 数据,是单个数据 + 事件变更的形式,所以用 BindableProperty 非常合适,可以少写很多代码。

    一般情况下,像主角的金币、分数等数据非常适合用 BindableProperty 的方式实现。

    好了 BindableProperty 我们就介绍到这里。

    更多内容

  • 相关阅读:
    Java 7 新的 try-with-resources 语句,自动资源释放
    单例模式在多线程下的问题
    设计模式-结构型模式
    设计模式-创建型模式
    【selenium】python+selenium+unittest,关于每次执行完一个测试用例都关闭浏览器等时间较长的问题之解决方案·续·装饰器
    【selenium】python+selenium+unittest,关于每次执行完一个测试用例都关闭浏览器等时间较长的问题之解决方案
    启动流程--CPU启动条件
    特殊估计制作(2): dump固件
    内存泄漏:lowmemory 相关调试
    寄存器调试 (2):应用层通过C代码访问
  • 原文地址:https://www.cnblogs.com/liangxiegame/p/16798154.html
Copyright © 2020-2023  润新知