QFramework v1.0 使用指南 架构篇:06. 引入 System-职场生存日志漫画

在这一篇,我们来引入最后一个基本概念 System。

首先我们来看下代码,如下:

using UnityEngine;using UnityEngine.UI;namespace QFramework.Example{        // 1. 定义一个 Model 对象    public class CounterAppModel : AbstractModel    {        private int mCount;        public int Count        {            get => mCount;            set            {                if (mCount != value)                {                    mCount = value;                    PlayerPrefs.SetInt(nameof(Count),mCount);                }            }        }        protected override void OnInit()        {            var storage = this.GetUtility<Storage>();            Count = storage.LoadInt(nameof(Count));            // 可以通过 CounterApp.Interface 监听数据变更事件            CounterApp.Interface.RegisterEvent<CountChangeEvent>(e =>            {                this.GetUtility<Storage>().SaveInt(nameof(Count), Count);            });        }    }    // 定义 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()        {            // 注册 Model            this.RegisterModel(new CounterAppModel());                        // 注册存储工具的对象            this.RegisterUtility(new Storage());        }    }        // 定义数据变更事件    public struct CountChangeEvent // ++    {            }        // 引入 Command    public class IncreaseCountCommand : AbstractCommand     {        protected override void OnExecute()        {            this.GetModel<CounterAppModel>().Count++;            this.SendEvent<CountChangeEvent>(); // ++        }    }        public class DecreaseCountCommand : AbstractCommand    {        protected override void OnExecute()        {            this.GetModel<CounterAppModel>().Count--;            this.SendEvent<CountChangeEvent>(); // ++        }    }    // 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(/* 这里可以传参(如果有) */));            });                        UpdateView();                        // 表现逻辑            this.RegisterEvent<CountChangeEvent>(e =>            {                UpdateView();            }).UnRegisterWhenGameObjectDestroyed(gameObject);        }                void UpdateView()        {            mCountText.text = mModel.Count.ToString();        }        // 3.        public IArchitecture GetArchitecture()        {            return CounterApp.Interface;        }        private void OnDestroy()        {            // 8. 将 Model 设置为空            mModel = null;        }    }}

这里我们假设一个功能,即策划提出了一个成就达成的功能,即 Count 到 10 的时候,触发一个点击达人成就,点击二十次 则触发一个 点击专家成就。

逻辑听起来很简单,我们直接在 IncreaseCountCommand 里编写即可,如下:

    public class IncreaseCountCommand : AbstractCommand     {        protected override void OnExecute()        {            var model = this.GetModel<CounterAppModel>();                            model.Count++;            this.SendEvent<CountChangeEvent>(); // ++            if (model.Count == 10)            {                Debug.Log("触发 点击达人 成就");            }            else if (model.Count == 20)            {                Debug.Log("触发 点击专家 成就");            }        }    }

代码很简单,我们运行测试一下。

运行之后,笔者点击了 20 次 + 号,结果如下:

这个功能很快就完成了。

但是这个时候策划说,希望再增加一个当点击 - 号到 -10 时,触发一个 点击菜鸟成就,然后策划还说,点击达人 和 点击专家 成就太容易达成了,需要分别改成 1000 次 和 2000 次。

而这次策划提出的需求,需要我们修改两处的代码,即 IncreaseCountCommand 里需要修改数值为 1000 和 2000,然后再 DecreaseCountCommand 增加一个判断逻辑。

一次提出的需求,结果造成了多处修改,这说明代码有问题。

首先像这种规则类的逻辑,比如分数统计或者成就统计等代码,不适合分散写在 Command 里,而适合统一写在一个对象里,而这种对象,在 QFramework 里有提供,就是 System 对象。

使用代码如下:

using UnityEngine;using UnityEngine.UI;namespace QFramework.Example{        // 1. 定义一个 Model 对象    public class CounterAppModel : AbstractModel    {        private int mCount;        public int Count        {            get => mCount;            set            {                if (mCount != value)                {                    mCount = value;                    PlayerPrefs.SetInt(nameof(Count),mCount);                }            }        }        protected override void OnInit()        {            var storage = this.GetUtility<Storage>();            Count = storage.LoadInt(nameof(Count));            // 可以通过 CounterApp.Interface 监听数据变更事件            CounterApp.Interface.RegisterEvent<CountChangeEvent>(e =>            {                this.GetUtility<Storage>().SaveInt(nameof(Count), Count);            });        }    }    public class AchievementSystem : AbstractSystem // +    {        protected override void OnInit()        {            var model = this.GetModel<CounterAppModel>();            this.RegisterEvent<CountChangeEvent>(e =>            {                if (model.Count == 10)                {                    Debug.Log("触发 点击达人 成就");                }                else if (model.Count == 20)                {                    Debug.Log("触发 点击专家 成就");                } else if (model.Count == -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());        }    }        // 定义数据变更事件    public struct CountChangeEvent // ++    {            }        // 引入 Command    public class IncreaseCountCommand : AbstractCommand     {        protected override void OnExecute()        {            var model = this.GetModel<CounterAppModel>();                            model.Count++;            this.SendEvent<CountChangeEvent>(); // ++        }    }        public class DecreaseCountCommand : AbstractCommand    {        protected override void OnExecute()        {            this.GetModel<CounterAppModel>().Count--;            this.SendEvent<CountChangeEvent>(); // ++        }    }    // 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(/* 这里可以传参(如果有) */));            });                        UpdateView();                        // 表现逻辑            this.RegisterEvent<CountChangeEvent>(e =>            {                UpdateView();            }).UnRegisterWhenGameObjectDestroyed(gameObject);        }                void UpdateView()        {            mCountText.text = mModel.Count.ToString();        }        // 3.        public IArchitecture GetArchitecture()        {            return CounterApp.Interface;        }        private void OnDestroy()        {            // 8. 将 Model 设置为空            mModel = null;        }    }}

代码越来越多,但是不难。

运行游戏,笔者点击的结果如下:

结果没问题。

好了,笔者写的成就系统非常简陋,实际上额度成就系统可以写得非常完善,比如可以再成就系统里进行存储加载等操作,而此文的成就系统仅仅是展示目的。

到此,我们就接触到了 QFramework 架构所提供的核心概念。

我们回顾一下第一篇的两张图,如下:

到此,大家应该能看懂这两张图了。

QFramework 总共分四个层级,即

表现层:IController

系统层:ISystem

数据层:IModel

工具层:IUtility

除了四个层级,还接触了为 Controller 的交互逻辑减负的 Command 和 为表现逻辑减负的 Event。

还有一个非常重要的 CQRS 原则的简易版本,Command->Model->State Changed Event。

到目前为止 QFramework 的基本用法我们过了一遍了。

从下一篇开始,我们开始介绍 QFramework 架构提供的剩余功能,这些功能是可选的。

这篇就到这里。

更多内容

转载请注明地址:liangxiegame.com (首发) 微信公众号:凉鞋的笔记

QFramework 主页:qframework.cn

QFramework 交流群: 623597263

QFramework Github 地址: https://github.com/liangxiegame/qframework

QFramework Gitee 地址:https://gitee.com/liangxiegame/QFramework

GamePix 独立游戏学院 & Unity 进阶小班地址:https://www.gamepixedu.com/

No.2533 小喜[35P/73M]
2023-05-23
10月18日,在这片大地上并不算特殊的一个日子,但因为一位卡普里尼,今天的罗德岛稍稍有些不同。莱塔尼亚的地质学者,叙拉古的天灾信使,维多利亚的糕点大师,汐斯塔的源石学者,他们可能是菲林,鲁珀,黎博利,又或者是萨科塔和萨卡兹,也许在这片天灾威胁下的土壤,他们往往出于种种必要或非必要的原因互相敌视,但在今天的罗德岛上,在此时的这间屋子内,所有人都怀揣着同样的心愿而来,为这位可爱,可怜,又可敬的卡普里尼少女,送上对她来到这片大地时刻的祝福。轻轻坐在地灵与普罗旺斯一起赠送的乐器前,少女将视线从粉色的眼眸
2022-10-18
[BoLoLi]BOL114 柳侑绮
2022-11-29
根据动画《蓝色反射 RAY/澪》的官方消息,原定于2021年7月28日发售的TV动画《蓝色反射 RAY/澪》的BD系列光盘,因故终止发售。已经付款的顾客,可通过预约的渠道进行退款。
2022-10-28
【QUEENIE CHUPPY】 Akali [25P 111MB]
2023-05-28
【Epicinternetgf】 Santa Yor [8P 27MB]
2023-01-22
给出一个字符串作为 key 和一个哈希表的大小,返回这个字符串的哈希值public int hashCode(String key, int hashSize) { long result = 0; char[] chars = key.toCharArray(); for (int i = 0; i < chars.length; i++) { result = (result * 33 + ((int) chars[i])) % hashSize; } return (int
2022-10-15
(C96)[みゃーのもと(宮本彩希)]ゆめゆめ彩希ゅばす---誘惑
2021-07-08
草房女牛仔【41P 68M】
2021-07-23
[pixiv]个人精挑windows桌面壁纸 分辨率均>2560x1440 [100P-622MB]
2023-05-17