# 06. 引入 System
在这一篇，我们来引入最后一个基本概念 System。

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

```csharp
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 里编写即可，如下：

```csharp
    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 次 + 号，结果如下：

![image.png](https://file.liangxiegame.com/826d5513-059e-41ba-8f5a-4fbea78dbde7.png)

这个功能很快就完成了。

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

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

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

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

使用代码如下:

```csharp
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;
        }
    }
}

```

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

运行游戏，笔者点击的结果如下：

![](https://file.liangxiegame.com/a1adc1e8-6bb9-49c1-ae74-e0e55673e865.png)

结果没问题。

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

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

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

![](https://file.liangxiegame.com/39bdcf54-0240-46e0-8f68-9eb708505695.png)



![](https://file.liangxiegame.com/6bf42306-0b2a-4417-bbcf-354af0132596.png)

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

QFramework 总共分四个层级，即
* 表现层：IController
* 系统层：ISystem
* 数据层：IModel
* 工具层：IUtility

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

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

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

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

这篇就到这里。

## 更多内容

*   转载请注明地址：[liangxiegame.com](https://liangxiegame.com) （首发） 微信公众号：凉鞋的笔记
*   QFramework 主页：[qframework.cn](https://qframework.cn)
*   QFramework 交流群: 623597263
*   QFramework Github 地址: [https://github.com/liangxiegame/qframework](https://github.com/liangxiegame/qframework)
*   QFramework Gitee 地址：[https://gitee.com/liangxiegame/QFramework](https://gitee.com/liangxiegame/QFramework)
*   GamePix 独立游戏学院 & Unity 进阶小班地址：[https://www.gamepixedu.com/](https://www.gamepixedu.com/)




