模型-视图-控制器模式,也称为MVC模式(Model View Controller)。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。它把软件系统分为三个基本部分:
模型(Model):负责存储系统的中心数据。
视图(View):将信息显示给用户(可以定义多个视图)。
控制器(Controller):处理用户输入的信息。负责从视图读取数据,控制用户输入,并向模型发送数据,是应用程序中处理用户交互的部分。负责管理与用户交互交互控制。
视图和控制器共同构成了用户接口。
且每个视图都有一个相关的控制器组件。控制器接受输入,通常作为将鼠标移动、鼠标按钮的活动或键盘输入编码的时间。时间被翻译成模型或试图的服务器请求。用户仅仅通过控制器与系统交互。

QFramework的MVC:
上面简单的介绍了什么是MVC,让有的同事进一步的了解一下。
QFramework 基于 MVC 的开发模式
所以我们先从最熟知的 MVC 架构开始着手 QFramework 的学习。
有些技术只靠文字不能形象的进行表达和说明,那么我们就通过一些简单的功能来反应技术的点有什么的不同之处
首先我们再unity中搭建一个简单的计数器功能,通过加减来控制技术器的数值变化:

然后我们用平时我们最常用的方法实现它
- using UnityEngine;
- using UnityEngine.UI;
-
- // Controller
- public class CounterAppController : MonoBehaviour
- {
- // View:在 QFramework 的 MVC 定义里就是提供关键组件的引用
- private Button mBtnAdd;
- private Button mBtnSub;
- private Text mCountText;
-
- // Model:非常简单,只有一个成员变量,但是在这里它其实并不算是一个 Model,他只是要在
- // View 中显示的一个数据而已
- private int mCount = 0;
-
- void Start()
- {
- // View 组件获取
- mBtnAdd = transform.Find("BtnAdd").GetComponent
- mBtnSub = transform.Find("BtnSub").GetComponent
- mCountText = transform.Find("CountText").GetComponent
(); -
-
- // 监听输入
- mBtnAdd.onClick.AddListener(() =>
- {
- // 交互逻辑
- mCount++;
- // 表现逻辑
- UpdateView();
- });
-
- mBtnSub.onClick.AddListener(() =>
- {
- // 交互逻辑
- mCount--;
- // 表现逻辑
- UpdateView();
- });
-
- UpdateView();
- }
-
- void UpdateView()
- {
- mCountText.text = mCount.ToString();
- }
- }
目前像技术器这样的逻辑,以上代码完全没有问题的,但是,如果需要添加大量的业务逻辑呢?我们想一下,可能有的同学说来什么功能就加什么功能呗。
其中很有可能让 mCount 在多个 Controller 中使用,甚至需要针对 mCount 这个数据写一些其他逻辑,比如增加 mCount 则增加 5 个分数,或者 mCount 需要存储等,总之 mCount 在未来可能会发展成一个需要共享的数据,而 mCount 目前只属于 CounterAppController,显然在未来这是不够用的。
我们就需要让 mCount 成员变量变成一个共享的数据,最快的做法是吧 mCount 变量变成静态变量或者单例,但是这样虽然写起来很快,但是在后期维护额度时候会产生很多的问题。而QFramework架构提供了Model的概念,那么我们就要用他的方法进行实现,那么当我们将QFramework导入工程之后,我们需要对代码进行修改:
- using UnityEngine;
- using UnityEngine.UI;
-
- // 1. 定义一个 Model 对象
- public class CounterAppModel : AbstractModel
- {
- public int Count;
-
- protected override void OnInit()
- {
- Count = 0;
- }
- }
-
-
- // 2.定义一个架构(提供 MVC、分层、模块管理等)
- public class CounterApp : Architecture<CounterApp>
- {
- protected override void Init()
- {
- // 注册 Model
- this.RegisterModel(new CounterAppModel());
- }
- }
-
- // 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(() =>
- {
- // 6. 交互逻辑
- mModel.Count++;
- // 表现逻辑
- UpdateView();
- });
-
- mBtnSub.onClick.AddListener(() =>
- {
- // 7. 交互逻辑
- mModel.Count--;
- // 表现逻辑
- UpdateView();
- });
-
- UpdateView();
- }
-
- void UpdateView()
- {
- mCountText.text = mModel.Count.ToString();
- }
-
- // 3.指定架构
- public IArchitecture GetArchitecture()
- {
- return CounterApp.Interface;
- }
-
- private void OnDestroy()
- {
- // 8. 将 Model 设置为空
- mModel = null;
- }
- }
代码引入了两个新的概念,一个是 Architecture,另一个是 Model。Architecture 用于管理模块,或者说 Architecture 提供一整套架构的解决方案,而模块管理和提供 MVC 只是其功能的一小部分。
这里要注意一点,Model 的引入是为了解决数据共享的问题,而不是说单只是为了让数据和表现分离,这一点是非常重要的一点。数据共享分两种:空间上的共享和时间上的共享。空间的共享很简单,就是多个点的代码需要访问 Model 里的数据。时间上的共享就是存储功能,将上一次关闭 App 之前的数据存储到一个文件里,这次打开时获得上次关闭 App 之前的数据。虽然我们上手了 MVC,但是这样的 MVC 还有很多问题,我们下一篇继续解决。