• QFramework引入Utility和System


    存储问题:

    在前面我们已经通过基础的学习了解了QFramework的架构以及引入Command和引入Event。那么

    如果我们想支持CounterApp的存储功能,应该如何做呢?

    如果时候未来我们需要存储的数据非常多的时候,Model 层就会充斥大量存储、加载相关的代码。

    还有就是,我们以后如果不想使用 PlayperPrefs 了,想使用 EasySave 或者 SQLite 的时候,就会

    造成大量的修改工作量。


    解决办法:

    于是 QFramework 提供了一个 Utility 层,专门用来解决上述两个问题的,使用方法非常简单:

    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. // 1. 定义一个 Model 对象
    4. public class CounterAppModel : AbstractModel
    5. {
    6. private int mCount;
    7. public int Count
    8. {
    9. get => mCount;
    10. set
    11. {
    12. if (mCount != value)
    13. {
    14. mCount = value;
    15. PlayerPrefs.SetInt(nameof(Count),mCount);
    16. }
    17. }
    18. }
    19. protected override void OnInit()
    20. {
    21. var storage = this.GetUtility();
    22. Count = storage.LoadInt(nameof(Count));
    23. // 可以通过 CounterApp.Interface 监听数据变更事件
    24. CounterApp.Interface.RegisterEvent(e =>
    25. {
    26. this.GetUtility().SaveInt(nameof(Count), Count);
    27. });
    28. }
    29. }
    30. // 定义 utility 层
    31. public class Storage : IUtility
    32. {
    33. public void SaveInt(string key, int value)
    34. {
    35. PlayerPrefs.SetInt(key,value);
    36. }
    37. public int LoadInt(string key, int defaultValue = 0)
    38. {
    39. return PlayerPrefs.GetInt(key, defaultValue);
    40. }
    41. }
    42. // 2.定义一个架构(提供 MVC、分层、模块管理等)
    43. public class CounterApp : Architecture<CounterApp>
    44. {
    45. protected override void Init()
    46. {
    47. // 注册 Model
    48. this.RegisterModel(new CounterAppModel());
    49. // 注册存储工具的对象
    50. this.RegisterUtility(new Storage());
    51. }
    52. }
    53. // 定义数据变更事件
    54. public struct CountChangeEvent // ++
    55. {
    56. }
    57. // 引入 Command
    58. public class IncreaseCountCommand : AbstractCommand
    59. {
    60. protected override void OnExecute()
    61. {
    62. this.GetModel().Count++;
    63. this.SendEvent(); // ++
    64. }
    65. }
    66. public class DecreaseCountCommand : AbstractCommand
    67. {
    68. protected override void OnExecute()
    69. {
    70. this.GetModel().Count--;
    71. this.SendEvent(); // ++
    72. }
    73. }
    74. // Controller
    75. public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
    76. {
    77. // View
    78. private Button mBtnAdd;
    79. private Button mBtnSub;
    80. private Text mCountText;
    81. // 4. Model
    82. private CounterAppModel mModel;
    83. void Start()
    84. {
    85. // 5. 获取模型
    86. mModel = this.GetModel();
    87. // View 组件获取
    88. mBtnAdd = transform.Find("BtnAdd").GetComponent
    89. mBtnSub = transform.Find("BtnSub").GetComponent
    90. mCountText = transform.Find("CountText").GetComponent();
    91. // 监听输入
    92. mBtnAdd.onClick.AddListener(() =>
    93. {
    94. // 交互逻辑
    95. this.SendCommand();
    96. });
    97. mBtnSub.onClick.AddListener(() =>
    98. {
    99. // 交互逻辑
    100. this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
    101. });
    102. UpdateView();
    103. // 表现逻辑
    104. this.RegisterEvent(e =>
    105. {
    106. UpdateView();
    107. }).UnRegisterWhenGameObjectDestroyed(gameObject);
    108. }
    109. void UpdateView()
    110. {
    111. mCountText.text = mModel.Count.ToString();
    112. }
    113. // 3.
    114. public IArchitecture GetArchitecture()
    115. {
    116. return CounterApp.Interface;
    117. }
    118. private void OnDestroy()
    119. {
    120. // 8. 将 Model 设置为空
    121. mModel = null;
    122. }
    123. }

    这样当我们,想要将 PlayerPrefs 方案替换成 EasySave 的时候,只需要对 Storage 里的代码进行修改即可。

    最后给出流程图,如下:

     


     成就问题:

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

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

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

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

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


    解决办法:

    代码如下:

    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. // 1. 定义一个 Model 对象
    4. public class CounterAppModel : AbstractModel
    5. {
    6. private int mCount;
    7. public int Count
    8. {
    9. get => mCount;
    10. set
    11. {
    12. if (mCount != value)
    13. {
    14. mCount = value;
    15. PlayerPrefs.SetInt(nameof(Count),mCount);
    16. }
    17. }
    18. }
    19. protected override void OnInit()
    20. {
    21. var storage = this.GetUtility();
    22. Count = storage.LoadInt(nameof(Count));
    23. // 可以通过 CounterApp.Interface 监听数据变更事件
    24. CounterApp.Interface.RegisterEvent(e =>
    25. {
    26. this.GetUtility().SaveInt(nameof(Count), Count);
    27. });
    28. }
    29. }
    30. public class AchievementSystem : AbstractSystem // +
    31. {
    32. protected override void OnInit()
    33. {
    34. var model = this.GetModel();
    35. this.RegisterEvent(e =>
    36. {
    37. if (model.Count == 10)
    38. {
    39. Debug.Log("触发 点击达人 成就");
    40. }
    41. else if (model.Count == 20)
    42. {
    43. Debug.Log("触发 点击专家 成就");
    44. } else if (model.Count == -10)
    45. {
    46. Debug.Log("触发 点击菜鸟 成就");
    47. }
    48. });
    49. }
    50. }
    51. // 定义 utility 层
    52. public class Storage : IUtility
    53. {
    54. public void SaveInt(string key, int value)
    55. {
    56. PlayerPrefs.SetInt(key,value);
    57. }
    58. public int LoadInt(string key, int defaultValue = 0)
    59. {
    60. return PlayerPrefs.GetInt(key, defaultValue);
    61. }
    62. }
    63. // 2.定义一个架构(提供 MVC、分层、模块管理等)
    64. public class CounterApp : Architecture<CounterApp>
    65. {
    66. protected override void Init()
    67. {
    68. // 注册 System
    69. this.RegisterSystem(new AchievementSystem()); // +
    70. // 注册 Model
    71. this.RegisterModel(new CounterAppModel());
    72. // 注册存储工具的对象
    73. this.RegisterUtility(new Storage());
    74. }
    75. }
    76. // 定义数据变更事件
    77. public struct CountChangeEvent // ++
    78. {
    79. }
    80. // 引入 Command
    81. public class IncreaseCountCommand : AbstractCommand
    82. {
    83. protected override void OnExecute()
    84. {
    85. var model = this.GetModel();
    86. model.Count++;
    87. this.SendEvent(); // ++
    88. }
    89. }
    90. public class DecreaseCountCommand : AbstractCommand
    91. {
    92. protected override void OnExecute()
    93. {
    94. this.GetModel().Count--;
    95. this.SendEvent(); // ++
    96. }
    97. }
    98. // Controller
    99. public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
    100. {
    101. // View
    102. private Button mBtnAdd;
    103. private Button mBtnSub;
    104. private Text mCountText;
    105. // 4. Model
    106. private CounterAppModel mModel;
    107. void Start()
    108. {
    109. // 5. 获取模型
    110. mModel = this.GetModel();
    111. // View 组件获取
    112. mBtnAdd = transform.Find("BtnAdd").GetComponent
    113. mBtnSub = transform.Find("BtnSub").GetComponent
    114. mCountText = transform.Find("CountText").GetComponent();
    115. // 监听输入
    116. mBtnAdd.onClick.AddListener(() =>
    117. {
    118. // 交互逻辑
    119. this.SendCommand();
    120. });
    121. mBtnSub.onClick.AddListener(() =>
    122. {
    123. // 交互逻辑
    124. this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
    125. });
    126. UpdateView();
    127. // 表现逻辑
    128. this.RegisterEvent(e =>
    129. {
    130. UpdateView();
    131. }).UnRegisterWhenGameObjectDestroyed(gameObject);
    132. }
    133. void UpdateView()
    134. {
    135. mCountText.text = mModel.Count.ToString();
    136. }
    137. // 3.
    138. public IArchitecture GetArchitecture()
    139. {
    140. return CounterApp.Interface;
    141. }
    142. private void OnDestroy()
    143. {
    144. // 8. 将 Model 设置为空
    145. mModel = null;
    146. }
    147. }

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

    QFramework 总共分四个层级,即

    • 表现层:IController
    • 系统层:ISystem
    • 数据层:IModel
    • 工具层:IUtility

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

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

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

  • 相关阅读:
    Spring的copy属性
    刘锦程荣获2022年度中国电商行业创新人物奖
    2022年《微信小程序从基础到uni-app项目实战》
    我梦想中的学习组织-勤学会
    大数据之力:从数据湖到数据智能的升级之路
    微信小程序开发---小程序的页面配置
    计算机三级UML与数据库应用系统练习题(一)
    【宋红康 MySQL数据库 】【高级篇】【19】多版本并发控制MVCC
    软件测试中如何测试算法?
    Qt应用开发(基础篇)——输入对话框 QInputDialog
  • 原文地址:https://blog.csdn.net/LiKe11807/article/details/126492101