在前面我们已经通过基础的学习了解了QFramework的架构以及引入Command和引入Event。那么
如果我们想支持CounterApp的存储功能,应该如何做呢?
如果时候未来我们需要存储的数据非常多的时候,Model 层就会充斥大量存储、加载相关的代码。
还有就是,我们以后如果不想使用 PlayperPrefs 了,想使用 EasySave 或者 SQLite 的时候,就会
造成大量的修改工作量。
于是 QFramework 提供了一个 Utility 层,专门用来解决上述两个问题的,使用方法非常简单:
- using UnityEngine;
- using UnityEngine.UI;
-
- // 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
(); -
- Count = storage.LoadInt(nameof(Count));
-
- // 可以通过 CounterApp.Interface 监听数据变更事件
- CounterApp.Interface.RegisterEvent
(e => - {
- this.GetUtility
().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
().Count++; - this.SendEvent
(); // ++ - }
- }
-
- public class DecreaseCountCommand : AbstractCommand
- {
- protected override void OnExecute()
- {
- this.GetModel
().Count--; - this.SendEvent
(); // ++ - }
- }
-
- // 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
(); -
- // View 组件获取
- mBtnAdd = transform.Find("BtnAdd").GetComponent
- mBtnSub = transform.Find("BtnSub").GetComponent
- mCountText = transform.Find("CountText").GetComponent
(); -
-
- // 监听输入
- mBtnAdd.onClick.AddListener(() =>
- {
- // 交互逻辑
- this.SendCommand
(); - });
-
- mBtnSub.onClick.AddListener(() =>
- {
- // 交互逻辑
- this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
- });
-
- UpdateView();
-
- // 表现逻辑
- this.RegisterEvent
(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;
- }
- }
这样当我们,想要将 PlayerPrefs 方案替换成 EasySave 的时候,只需要对 Storage 里的代码进行修改即可。
最后给出流程图,如下:

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

但是这个时候策划说,希望再增加一个当点击 - 号到 -10 时,触发一个 点击菜鸟成就,然后策划还说,点击达人 和 点击专家 成就太容易达成了,需要分别改成 1000 次 和 2000 次。
而这次策划提出的需求,需要我们修改两处的代码,即 IncreaseCountCommand 里需要修改数值为 1000 和 2000,然后再 DecreaseCountCommand 增加一个判断逻辑。
一次提出的需求,结果造成了多处修改,这说明代码有问题。
首先像这种规则类的逻辑,比如分数统计或者成就统计等代码,不适合分散写在 Command 里,而适合统一写在一个对象里,而这种对象,在 QFramework 里有提供,就是 System 对象。
代码如下:
- using UnityEngine;
- using UnityEngine.UI;
-
- // 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
(); -
- Count = storage.LoadInt(nameof(Count));
-
- // 可以通过 CounterApp.Interface 监听数据变更事件
- CounterApp.Interface.RegisterEvent
(e => - {
- this.GetUtility
().SaveInt(nameof(Count), Count); - });
- }
- }
-
-
- public class AchievementSystem : AbstractSystem // +
- {
- protected override void OnInit()
- {
- var model = this.GetModel
(); -
- this.RegisterEvent
(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
(); -
- model.Count++;
- this.SendEvent
(); // ++ - }
- }
-
- public class DecreaseCountCommand : AbstractCommand
- {
- protected override void OnExecute()
- {
- this.GetModel
().Count--; - this.SendEvent
(); // ++ - }
- }
-
- // 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
(); -
- // View 组件获取
- mBtnAdd = transform.Find("BtnAdd").GetComponent
- mBtnSub = transform.Find("BtnSub").GetComponent
- mCountText = transform.Find("CountText").GetComponent
(); -
-
- // 监听输入
- mBtnAdd.onClick.AddListener(() =>
- {
- // 交互逻辑
- this.SendCommand
(); - });
-
- mBtnSub.onClick.AddListener(() =>
- {
- // 交互逻辑
- this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
- });
-
- UpdateView();
-
- // 表现逻辑
- this.RegisterEvent
(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 总共分四个层级,即
除了四个层级,还接触了为 Controller 的交互逻辑减负的 Command 和 为表现逻辑减负的 Event。
还有一个非常重要的 CQRS 原则的简易版本,Command->Model->State Changed Event。
到目前为止 QFramework 的基本用法我们过了一遍了。