MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发,通过使用这种设计模式可以有效的实现各个功能的模块化,也可以更好地实现模块内部和模块间数据、业务逻辑、交互界面的分离。
通过这种形式的分离可以保证我们在开发应用的过程中能够专注于一个方面,例如在开发Model的时候只需要关注如何设计数据结构、提供数据修改的接口以及数据发生变动时通知对应的显示界面;在开发Controller的时候只需要关注业务逻辑如何实现,按照需求修改对应Model的数据;开发View的时候只需要监听数据的变化让UI做出响应,提供交互功能实现用户对数据的修改。
Model中包含了这一个业务模块所包含的数据结构,这里所说的数据结构并不是单纯的保存在用户私有数据中的数据结构(如:当前关卡,金币余额等),而是在应用运行过程中根据用户保存于本地(或服务器)上的私有数据动态创建的数据,是内存中的数据结构。
除了提供数据结构外Model还需要在数据发生变化时通知View层,使其做出响应。Unity中这一步可以通过委托来实现,下文会介绍到。
View中定义了数据要以何种形式展示,是数据的窗口。
需要注意的是View和Model并非一对一的关系,而是多对多的关系,一个View可能会展示几个Model的数据,同样一个Model的数据也可能会在多个View中展示。
举个栗子,在游戏主界面上可能包含有金币余额、钻石余额、签到天数、装备信息等等,这就涉及到了用户模块、签到模块、装备模块。如果强行为每个模块对应一个View的化可能会导致整个UI架构变琐碎、难以维护。
View层并不等于UI界面,可以把它抽象为数据展示层,在对玩家角色的位置、装备信息、血量等数据进行展示时,View层就变成了游戏场景,而非UI界面。
View同样还需要提供如按钮点击、射线检测等功能,是用户通过Controller对数据进行修改的起点。
Controller中规定了当用户传入参数或进行操作时应该以何种方式修改Model中的数据,是修改Model中数据唯一的入口。
Controller与View可以是一对一的关系,也就是说为一个Model配一个Controller作为它的管理类,这种方式可以防止Controller对其他模块Model中数据的引用,如果必须访问则需要通过对应的Controller进行访问。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;
namespace MVCBase
{
public delegate void OnValueChange(V val);
///
/// Model基类
///
/// 本地数据泛型
public class BaseModel : Singleton where T : new() where D : new()
{
///
/// 本地存储数据的Key, 默认为""
///
protected virtual string GetLocalDataKey()
{
return "";
}
///
/// 本地数据
///
protected D localData = new D();
///
/// 初始化流程,请务必在使用前调用
///
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(localDataStr);
}
///
/// 初始化本地数据
///
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;
///
/// 测试模块
/// 因为不需要本地数据所以对应泛型选择Object,LocalDataKey用默认值
///
public class TestModel : BaseModel
{
///
/// 金币数额变化时执行委托
///
public OnValueChange OnCoinChange;
///
/// 钻石数额变化时执行委托
///
public OnValueChange 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;
///
/// 测试Controller
/// 提供修改金币和钻石的接口
///
public class TestController : MonoSingleton
{
private void Start()
{
TestModel.Instance.Init();
}
///
/// 修改金币的接口
///
///
public void ChangeCoin(int delat)
{
TestModel.Instance.Coin += delat;
}
///
/// 修改钻石的接口
///
///
public void ChangeDiamond(int delat)
{
TestModel.Instance.Diamond += delat;
}
}
TestView
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
///
/// 测试View
/// CoinText和DiamondText负责金币和钻石数量的显示
/// 在场景中添加按钮绑定修改金币和钻石的接口
///
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;
}
///
/// 添加金币的接口
///
public void AddCoin()
{
TestController.Instance.ChangeCoin(100);
}
///
/// 扣除金币的接口
///
public void ReduceCoin()
{
TestController.Instance.ChangeCoin(-80);
}
///
/// 添加钻石的接口
///
public void AddDiamond()
{
TestController.Instance.ChangeDiamond(20);
}
///
/// 扣除钻石的接口
///
public void ReduceDiamond()
{
TestController.Instance.ChangeDiamond(-50);
}
}
项目地址:MVCFrame: 在Unity中实现MVC架构
点击对应按钮即可修改Model中的数据,数据变化的同时会通知UI界面刷新数据显示