實際專案中的 MVVM(積木)模式第二章:model –如何高效利用資料層

發表於2016-06-03

“不為炫技而炫技,不為架構而設計架構,只為寫出一個接地氣、通俗易懂的使用方法”

(注:瞭解整個設計模式體系請檢視我上篇文章實際專案中的MVVM(積木)模式:序章

這篇文章講解Model和ViewModel。

本著易擴充套件、易理解的前提,講解中Model和ViewModel都用最基礎的方法和易理解的思維圖。

為何為何會將View和ViewModel合併在一起講解?為何我會將有些文章說的的網路層與資料層合併一起叫資料層?

很簡單,我們需要明白一個道理,無論是網路請求還是本地快取,本質上都是傳遞資料;因此,我們要做的就是將各種來源的資料通過資料加工(ViewModel)形成統一的格式(Model)再通過一個統一的介面傳遞給需要的地方。我所講的資料層,我把這形象地叫為資料工廠。

1677606-3f51b057983b90a0

資料工廠

首先,我們先開始說說:Model。

一、Model–專案的資訊承載與傳遞者

一個多人協同開發的專案,保證資料結構的一致性和穩定是很有必要的。而Model則是很好的實現了這一需求。
首先,我們先通過三個大的方面將字典與Model作一個比較,更直觀瞭解Model的特點。

1、字典與模型的比較

a、取值:字典會因為沒有取值的這個key或者這個錯誤的key剛好是這個字典中其他型別的值對應的key(因輸入錯誤等原因),通過這個key取出來的值為nil或者其他型別的值,如賦值給label之類的文字控制元件,可能會導致程式崩潰,而Model不會出現這樣的問題;
b、資料展示:字典無法再不改變資料來源的前提下,改變資料的格式,而Model則可以通過get方法實現這個需求,保證了資料的原始性和可變性;
c、後期維護:字典每個key的具體含義和有多少key要通過介面文件去了解,而Model體現在具體的屬性和每個屬性的備註上;
可能有同學會問建立Model一個個去複製貼上屬性好麻煩,還有像資料快取之類還要一個個寫解擋歸檔好麻煩呢/(ㄒoㄒ)/~~
這麼多好的優點的前提下,這幾個小麻煩肯定會通過方法解決噻,且看下面:

2、解決Model的一些小麻煩

a、如何快速建立Model:這裡有份程式碼,可以將網路請求下來的字典裡的key在控制檯列印成Model裡的屬性格式哦。(列印效果在程式碼塊下面)

看下圖列印效果,那麼列印出來的效果大家知道了吧,直接複製貼上就OK啦:
 
1677606-7c2a2c2dee177204

列印效果

b、怎麼解決繁瑣的解擋歸檔呢

在BaseModel(Model的基類)中寫一個統一的解擋、歸檔,這裡就要用到runtime中非常有用的兩個方法:

那麼具體怎麼在基類寫一個,所有適用呢,且看下面:

至此,所有繼承於這個Model基類的Model都自動實現瞭解檔歸檔的方法。
既然解決了建立Model的一些小麻煩,我們就來構建一個專案中標準的BaseModel(基類模型)。

3、何為基類Model建立要求?

a、資料格式讀取統一與寫入統一;
b、模型屬性值可批量修改;

這樣才能保證在“千奇百怪、朝令夕改”的資料來源中,進入到這個專案體系後,面向業務工程師的時候,是統一整齊的標準模型,然後業務工程師才會在這個基礎之上擴充套件其他子Model。
其中讀寫統一則是通過上面的解檔歸檔解決,而模型屬性值批量修改則是通過李明傑大神的MJExtension(這個三方庫可以在不用繼承其他Model前提下使用,保證了Model獨立性),具體程式碼在BaseModel如下:

以上程式碼舉了部分替換的例子,目的是告訴大家通過這方法可以在資料來源傳給客戶端是非友好資料的時候,我們客戶端能夠進行處理,給業務工程師一個友好的資料。這對資料工廠這個模式來說是非常有必要的。
至此,BaseModel就只有寫兩個方法:解檔與歸檔 以及 屬性值批量修改。因為我們始終要明白:Model是來保證整個專案架構資料結構的一致性和穩定性。那麼繼承這個BaseModel的子Model就都具備了面向業務工程師友好資料的特點。

那麼如何正確使用子Model呢?
我舉兩個例子:

1、如何將模型源資料的時間 20161010 變成 2016-10-10(正確使用get方法)

這樣的好處有兩方面:一方面,業務工程師不會修改源資料,保證了源資料的安全性;另一方面,類似formatDateString的方法,是通過Category(也就是我後面要說的工具類)使用的,保證了程式碼的低耦合性。

2、使用子Model分離資料的一個例子(這個例子感謝我的同事 張爾柏 同學提供,展示這個例子主要目的是為了表達子Model其中一個在cell樣式資料分離的作用,可能會因為沒有demo,大家不太好理解。所以,大家可以在後期demo上傳後再次詳細瞭解)

這裡我們舉個tableView中Cell顯示(整個tableView的demo將會在View篇結束後放出),其中Model要做的事情,我們先看在Model中的程式碼:

通過在Model生成時執行這個方法,實現了Cell樣式與樣式資料分離,做到了每個Cell的View樣式與Model的繫結。

在講解Model的結尾,總結起來就是:Model存在的目的是為了給業務工程師一個友好穩定的資料,讓業務工程師在相應的模組內獨立地做相應的資料操作。

二、ViewModel–做一個優秀的資料工廠

如文章開始的圖就知道,ViewModel更像一個食品工廠一樣,將不同的原料通過不同的製作工藝產出為統一的產品。
那麼作為工廠的框架BaseViewModel應該是怎樣的呢?
首先我們應該先想到,我們的原料(資料)來自哪裡?
基本都是來自網路了噻!
既然來自網路,那麼就明確了BaseViewModel應該實現三個事情:網路通訊、上傳、下載。(都用af第三方庫實現)
廢話不多說,直接上程式碼:

1、BaseViewModel實現的三個方法

網路請求:

上傳:
該上傳方法需要求能同時多傳,且傳不同型別的檔案,以適應不用的場景需要

下載:

2.如何寫好一個子ViewModel

不知道大家注意到沒有,其實我們真實的專案中,網路請求返回來的狀態其實可能是會存在三種狀態的:請求成功;請求失敗,伺服器返回錯誤資訊;請求失敗,網路不通。同時,我們會在某些地方做快取讀寫。那既然如此,繼承BaseViewModel的子ViewModel的對外介面(唯一對外介面)應是如下所寫:

3、到底ViewModel放在哪裡合適?建立多少個ViewModel合適?

開門見山直說,個人認為只要涉及資料的View的模組,最理想的情況應該一個View模組一個ViewModel。
因為,只有這樣,在後期專案越來越龐大,維護的人員越來越多的時候,才能保證模組之間的絕對獨立。
(如果是一兩個人開發的中小型專案,也沒必要一個模組對一個ViewModel,本身功能不多,沒有必要。這時可以一個Controller對一個ViewModel,或者幾個同需求功能的Controller對一個ViewModel。專案死的,人是靈活的,具體情況具體分析。)

我舉兩個例子:

a.某個模組因為維護人員頻次多,需求改動頻繁,到最後需要大改某個模組的時候,因為之前的至上到下(資料到介面)的絕對獨立,可以完全抽出來,重新制作一個新的模組,重新替換進去;
b.某些模組需要資料快取,某些模組又需要網路狀態判斷(含大圖片展示的模組),完全可以針對不同情況針對這些相應模組對應的ViewModel資料工廠做相應的事情。
以上兩個例子,我想做過專案的,尤其是遇到頻繁更改需求的,應該是深有體會(哎,我本人就特別有體會/(ㄒoㄒ)/~~)。


借用一位大神的話結束Model篇:

“你必須得清楚你要做什麼,業務方希望要什麼。而不是為了架構而架構,也不是為了體驗新技術而改架構方案。以前是MVC,最近流行MVVM,如果過去的MVC是個好架構,沒什麼特別大的缺陷,就不要推倒然後搞成MVVM。”

後面幾天我在各位大神的建議下會不斷優化文章各個細節,歡迎多多關注,共同學習。幾天後會發出 view–業務與介面結合的模組開發 請多關注。

相關文章