MVC的理解和实际应用
序
M=Model
V=View
C=Crontroller
其实百度呀,各种资料呀说一大堆,基本概念是 显示,控制,数据分离。
MFC在我的理解中,目的是更清楚的模块定义,耦合度更低,代码调用的时间轴更清晰,代码的调用关系更清晰。
我自己这几年的工作经验整理一下我对于MVC的理解和使用
Data
Logic
View
Net
Loader
Common
引用关系
Data Logic View 为一个组?一个功能?一个系统,具备这么几个组件。
Net Loader Common 是功能的底层功能。
Data <- Loader
Data <- Common
Logic <-Data
Logic <-Loader
Logic <-Common
Logic <-Net
View <-Logic
View <-Loader
View <-Common
View <-Net
Net <-Common
Loader <- Common
描述:
Data 数据层
数据层 分 静态数据层 网络数据层
1.静态数据 客户端读取配置保存在内存
2.网络数据 由服务器发送给客户端的数据,作为网络数据保存,网络数据是动态数据,是否清空按照功能需求而定
不论是静态数据还是网络数据,都应该是受到保护的Private。外部不应该直接对外保护,也就是外部不能直接对数据进行访问和修改。
静态数据由于是读取的本地配置,本地配置数据是原始数据,可以进行修改,所以一定是只读数据。整个项目内也不可能出现需要对静态数据做修改的操作。
Logic逻辑层
1.网络数据部分
是对服务器返回的网络数据做Set 和 Get的函数,对外开放。
客户端本地操作的Set需要确认操作逻辑的安全性,因为程序本身无法确保数据修改是安全的。
网络层应该无脑的向网络数据存储的数据结构做添加or插入,按照具体功能操作。
Get是对其他Logic和View层暴露 。
2.对网络层的封装
是对网络层 Request和Response方法的封装
因为在这套设计里,Logic逻辑层是一个单例的存在,所以界面操作或者逻辑流程可以直接静态调用对应功能的逻辑层的Request函数,向服务器请求数据。
服务器返回数据后,由网络层抛出到各个功能模块进行处理。
Logic监听Response消息,并且进行处理。 处理 包括保存数据到网络数据的数据结构中,和通知其他功能的逻辑层。
View 视图层
那这个就很易懂了,显示相关的。
界面上的MonoBehaviour相关的扒拉扒拉扒拉一堆。
很多操作其实是放在View层的,所以这么区分逻辑层和视图层,其实很简单,逻辑层主要操作数据,视图层主要操作显示。很多强联网的游戏可能没什么感觉,因为每次操作都和服务器通讯
那么
View点击 -> Logic发送消息 -> server …等待服务器返回 -> Logic保存数据 -> View刷新
所在在这套流程里基本不需要进行区分,各司其事其实很明确。
在短链接的游戏或者通讯频率比较低的?一些项目。比如背包的功能,客户端完全可以一顿操作,调整位置整理呀,之后再发给服务器,那么在我的理解中
View操作缓存数据在View层 -> View刷新 -> Logic发送消息 -> server …等待服务器返回 -> Logic保存数据 -> View检查数据同步 -> View刷新
或者是
View操作 -> View刷新,并且缓存数据在Logic层 -> Logic发送消息 -> server …等待服务器返回 -> Logic保存数据 -> View检查数据同步 -> View刷新
其实流程怎么样是无所谓的,只要合理,就是对的。
Net 网络层
这部分就暂时不说了,其实网络部分的牵涉系统底层。我只了解TCP Socket。UDP什么的,我并不了解。对于TCP相关的,之后有机会再发文章。
Loader 加载器
这部分学问就大了,Unity的内存管理,虽然说不难吧,但是也有很多注意点。这个也是以后再发。
代码:
/// <summary>
/// 一个背包格子的内容;
/// </summary>
public class BagItem
{
public int m_nID = 0; // 物品ID
/*
* 其他属性;
*/
}
/// <summary>
/// 一个道具的内容;
/// </summary>
public class ItemInfo
{
public string m_strName = "";
/*
* 其他属性;
*/
}
public class ItemData
{
private static Dictionary<int, ItemInfo> m_dicBagItems = new Dictionary<int, ItemInfo>(); // 道具ID to 道具信息
public static ItemInfo GetItem(int nID)
{
return null;
}
}
/// <summary>
/// Logic层
/// </summary>
public class BagLogic
{
private static Dictionary<int, BagItem> m_dicBagItems = new Dictionary<int, BagItem>(); //格子ID to 格子信息
public static void Init()
{
// 注册网络消息监听一个消息的CallBack:OnMsgCallBack
}
public static void Release()
{
// 对应Init,移除一个消息的监听;
}
public static void OnMsgCallBack(/*(此处应该有消息内容)*/)
{
//保存到 m_dicBagItems中
}
public static BagItem GetItem()
{
return null;
}
}
/// <summary>
/// View层
/// </summary>
public class UIBag : MonoBehaviour
{
void Start()
{
// 注册网络消息监听一个消息的CallBack:OnMsgCallBack
}
void OnDestroy() // 按照UI管理方法的不同,离开界面是自定义的?还是disable?还是destory?看个人情况
{
// 对应Init,移除一个消息的监听;
}
public void OnMsgCallBack(/*(此处应该有消息内容)*/)
{
BagItem bi = BagLogic.GetItem(); // 通过Logic获取
ItemInfo getItem = ItemData.GetItem(bi.m_nID); // 获取静态数据。 静态数据这块 是封装进Logic还是直接调用,其实在我看来没差。还是看具体功能而定。
//然后把数据刷新到界面上。
}
}
/// <summary>
/// 游戏的主入口;
/// </summary>
public class GameMain : MonoBehaviour
{
void Main()
{
BagLogic.Init(); // 在游戏开始的时候先注册,那么Logic监听消息的时间一定优先于后打开的界面,因为界面的消息监听是打开后才注册的。网络层向上抛数据一定是有序的。不然这个网络层,可以重写了。
}
}
程序学无止尽。
欢迎大家沟通,有啥不明确的,或者不对的,也可以和我私聊
我的QQ 334524067 神一般的狄狄