简介

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发,通过使用这种设计模式可以有效的实现各个功能的模块化,也可以更好地实现模块内部和模块间数据、业务逻辑、交互界面的分离。

通过这种形式的分离可以保证我们在开发应用的过程中能够专注于一个方面,例如在开发Model的时候只需要关注如何设计数据结构、提供数据修改的接口以及数据发生变动时通知对应的显示界面;在开发Controller的时候只需要关注业务逻辑如何实现,按照需求修改对应Model的数据;开发View的时候只需要监听数据的变化让UI做出响应,提供交互功能实现用户对数据的修改。

详细介绍

组成部分

M(Model)—— 模型

Model中包含了这一个业务模块所包含的数据结构,这里所说的数据结构并不是单纯的保存在用户私有数据中的数据结构(如:当前关卡,金币余额等),而是在应用运行过程中根据用户保存于本地(或服务器)上的私有数据动态创建的数据,是内存中的数据结构。

除了提供数据结构外Model还需要在数据发生变化时通知View层,使其做出响应。Unity中这一步可以通过委托来实现,下文会介绍到。

V(View)—— 视图

View中定义了数据要以何种形式展示,是数据的窗口。

需要注意的是View和Model并非一对一的关系,而是多对多的关系,一个View可能会展示几个Model的数据,同样一个Model的数据也可能会在多个View中展示。

举个栗子,在游戏主界面上可能包含有金币余额、钻石余额、签到天数、装备信息等等,这就涉及到了用户模块、签到模块、装备模块。如果强行为每个模块对应一个View的化可能会导致整个UI架构变琐碎、难以维护。

View层并不等于UI界面,可以把它抽象为数据展示层,在对玩家角色的位置、装备信息、血量等数据进行展示时,View层就变成了游戏场景,而非UI界面。

View同样还需要提供如按钮点击、射线检测等功能,是用户通过Controller对数据进行修改的起点。

C(Controller)—— 业务控制器

Controller中规定了当用户传入参数或进行操作时应该以何种方式修改Model中的数据,是修改Model中数据唯一的入口。

Controller与View可以是一对一的关系,也就是说为一个Model配一个Controller作为它的管理类,这种方式可以防止Controller对其他模块Model中数据的引用,如果必须访问则需要通过对应的Controller进行访问。

代码实现

BaseModel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;namespace MVCBase
{public delegate void OnValueChange<V>(V val);/// <summary>/// Model基类/// </summary>/// <typeparam name="D">本地数据泛型</typeparam>public class BaseModel<T, D> : Singleton<T> where T : new() where D : new(){/// <summary>/// 本地存储数据的Key, 默认为""/// </summary>protected virtual string GetLocalDataKey(){return "";}/// <summary>/// 本地数据/// </summary>protected D localData = new D();/// <summary>/// 初始化流程,请务必在使用前调用/// </summary>public void Init(){// 先读取本地数据GetLocalData();// 在初始化Model中使用到的数据结构InitData();}private void GetLocalData(){if (GetLocalDataKey() == ""){return;}string localDataStr = PlayerPrefs.GetString(GetLocalDataKey(), "");if (localDataStr == null || localDataStr == ""){return;}localData = JsonMapper.ToObject<D>(localDataStr);}/// <summary>/// 初始化本地数据/// </summary>protected virtual void InitData() { }protected void SaveLocalData(){if (GetLocalDataKey() == ""){return;}if (localData == null){Debug.LogError("local data is null, key: " + GetLocalDataKey());return;}string localDataStr = JsonMapper.ToJson(localData);PlayerPrefs.SetString(GetLocalDataKey(), localDataStr);}}
}public class BaseLocalData { }

TestModel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MVCBase;/// <summary>
/// 测试模块
/// 因为不需要本地数据所以对应泛型选择Object,LocalDataKey用默认值
/// </summary>
public class TestModel : BaseModel<TestModel, Object>
{/// <summary>/// 金币数额变化时执行委托/// </summary>public OnValueChange<int> OnCoinChange;/// <summary>/// 钻石数额变化时执行委托/// </summary>public OnValueChange<int> OnDiamondChange;private int coin = 0;public int Coin{get{return coin;}set{coin = value;if (OnCoinChange != null){OnCoinChange(coin);}}}private int diamond = 0;public int Diamond{get{return diamond;}set{diamond = value;if (OnDiamondChange != null){OnDiamondChange(diamond);}}}}

TestController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 测试Controller
/// 提供修改金币和钻石的接口
/// </summary>
public class TestController : MonoSingleton<TestController>
{private void Start(){TestModel.Instance.Init();}/// <summary>/// 修改金币的接口/// </summary>/// <param name="delat"></param>public void ChangeCoin(int delat){TestModel.Instance.Coin += delat;}/// <summary>/// 修改钻石的接口/// </summary>/// <param name="delat"></param>public void ChangeDiamond(int delat){TestModel.Instance.Diamond += delat;}
}

TestView

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;/// <summary>
/// 测试View
/// CoinText和DiamondText负责金币和钻石数量的显示
/// 在场景中添加按钮绑定修改金币和钻石的接口
/// </summary>
public class TestView : MonoBehaviour
{public Text coinText;public Text diamondText;private void Start(){TestModel.Instance.OnCoinChange += RefreshCoin;TestModel.Instance.OnDiamondChange += RefreshDiamond;coinText.text = "金币:" + TestModel.Instance.Coin;diamondText.text = "钻石:" + TestModel.Instance.Diamond;}private void RefreshCoin(int value){coinText.text = "金币:" + value;}private void RefreshDiamond(int value){diamondText.text = "钻石:" + value;}/// <summary>/// 添加金币的接口/// </summary>public void AddCoin(){TestController.Instance.ChangeCoin(100);}/// <summary>/// 扣除金币的接口/// </summary>public void ReduceCoin(){TestController.Instance.ChangeCoin(-80);}/// <summary>/// 添加钻石的接口/// </summary>public void AddDiamond(){TestController.Instance.ChangeDiamond(20);}/// <summary>/// 扣除钻石的接口/// </summary>public void ReduceDiamond(){TestController.Instance.ChangeDiamond(-50);}
}

项目地址:MVCFrame: 在Unity中实现MVC架构

运行效果:

点击对应按钮即可修改Model中的数据,数据变化的同时会通知UI界面刷新数据显示

在Unity中实现基础的MVC架构相关推荐

  1. Unity 中带你写MVC架构

    1.什么是MVC MVC分别代表Model - View - Controller Model - 模型层,也就是说,他只负责数据 View - 视图层,也就是说,他只负责更新UI Controlle ...

  2. 【贪玩巴斯】Unity3D初学圣经(三)—— unity中的基础概念——scene场景,component组件,assets文件夹和Material材质,Mesh Renderer与shader

    [贪玩巴斯]Unity3D初学圣经 三-- unity中的基础概念--scene场景,component组件与assets文件夹和Material材质以及Mesh Renderer 和 shader ...

  3. unity入门精要之第6 章 Unity 中的基础光照--环境光和自发光

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.Unity 中的环境光和自发光 二.在Unity Shader 中实现漫反射光照模型 参考 前言 但这种模型有很多局限性.首先,有很 ...

  4. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

  5. Unity 中的基础光照

    通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑三种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交:一些光被物体吸收了,而另一些光被散射到其他方向. 最后,摄像 ...

  6. unity入门精要之第6 章 Unity 中的基础光照---实现高光反射光照模型

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 参考 前言 在6.2.4 节中,我们给出了基本光照模型中高光反射部分的计算公式: 从公式可以看出,要计算高光反射需要知道4 个参数:入射 ...

  7. unity入门精要之第6 章 Unity 中的基础光照概述-1

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 6.1 我们是如何看到这个世界的 6.2 标准光照模型 参考 前言 渲染总是围绕着一个基础问题:我们如何决定一个像素的颜色?从宏观上来说 ...

  8. MVC架构在Asp.net中的应用和实现

    MVC架构在Asp.net中的应用和实现 摘要:本文主要论述了MVC架构的原理.优缺点以及MVC所能为Web应用带来的好处.并以"成都市信息化资产管理系统"框架设计为例,详细介绍其 ...

  9. Photon在unity中的使用

    ps:期末老师要求的一篇3000字的玩具级别论文,基本是官网和api手册原本就有的.基本我就是个搬运工,不知道有什么用,就先扔上来了.用的是writage,让word转为markdown,可能会出现一 ...

最新文章

  1. 我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案...
  2. Google App Engine使用简介
  3. android 模糊读取文件名_Android 从路径中获取文件名 | 学步园
  4. Oracle应用迁移到AnalyticDB for PostgreSQL指导
  5. The example program of C on point
  6. JQuery的ajaxFileUpload的使用
  7. python函数降低编程复杂度_Python-面向对象编程
  8. 动辄350亿被盗,区块链安全真就如此不堪一击?
  9. JavaScript权威指南--chapter 8函数
  10. 解决在IE下“JSON”未定义的有关问题
  11. java基础学习(9)堆和栈的区别详解
  12. matlab解三角函数方程某值附近,matlab解三角函数已知参数方程
  13. (SWAT-1)SWAT进行流域提取
  14. 关于Xray中代理的一些总结
  15. 撸一个聊天室(vue+koa2+websokect+mongodb)
  16. 左右滑屏设置_王者荣耀怎么滑屏操作 滑屏手法详解[多图]
  17. C语言---移盘子----Hanoi(汉诺)塔问题,显示移动盘子的步骤
  18. 论文翻译之Enriched Feature Guided Refinement Network for Object Detection
  19. Win10 系统一天蓝屏好多次,怎么解决?
  20. 趋势跟踪策略失效了,哈丁和他的元盛该怎么办?

热门文章

  1. 从任何字符串中提取IP
  2. 软工网络15个人作业3——案例分析 201521123056 吴剑通
  3. Unity 之 UGUI 图片 和 粒子特效显示层级关系调整
  4. 曹操最出名的4首诗赏析
  5. 使用selenium自动登陆滴滴打码网
  6. 时钟集成电路 Aip8563 MSOP8 简介
  7. 大电流滑环结构特征有哪些
  8. 教培行业如何打造高效益视频号
  9. 判断101-200之间有多少个素数,并输出所有素数
  10. google浏览器安装vuejs-devtools插件2022年安装记录