1. 程式人生 > >MVC的理解和實際應用

MVC的理解和實際應用

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 神一般的狄狄