再談MVVM

前言

MVVM設(shè)計模式自2005年被微軟提出以來,在應(yīng)用開發(fā)領(lǐng)域獲得了長久的發(fā)展。iOS開發(fā)過程中,Apple推薦的MVC模式,因其廣泛詬病的massive viewcontroller,逐漸被解耦更充分的MVVM替代。
本質(zhì)來說,MVVM跟MVC同屬于MV(X)類型的模式,是解決開發(fā)中model層與UI層解耦的方案。MVVM的優(yōu)點在于,通過架設(shè)viewmodel層(提供連接model和view層的中間件),解決了model和view在MVC controller(MVC中的C)的耦合。
MVVM的原理和優(yōu)點不在贅述,參見概念圖:


MVVM.png

Problem

考慮上圖的左側(cè)(view與viewmodel解耦):在實際使用過程中,通過viewmodel與view層狀態(tài)量綁定,很好的解決了view層耦合,解放了viewcontroller,使其更專注于view的組合和管理。同時,viewmodel對model的更新和監(jiān)聽,轉(zhuǎn)化為view層狀態(tài)量的處理,使我們可以在viewmodel專注于view層頁面量數(shù)據(jù)更新。
再考慮上圖右側(cè):我們通常習(xí)慣于在viewmodel層來處理model數(shù)據(jù),隨著業(yè)務(wù)的增多,viewmodel中充斥了接口的調(diào)用、model的轉(zhuǎn)化、數(shù)據(jù)的拼裝,再加上對view層頁面量的轉(zhuǎn)化,viewmodel同樣面臨著massive化的問題。
另外,viewmodel處理的model層數(shù)據(jù)越多,也代表著viewmodel與model的耦合度不斷上升。某些數(shù)據(jù)可能會涉及到session維護(hù),即數(shù)據(jù)也有著生命周期的管理,例如TCP長連的推送,歷史數(shù)據(jù)和當(dāng)前數(shù)據(jù)管理等等。那么對于這些可獨立的操作,這一塊model層數(shù)據(jù)處理,也具有復(fù)用的需求,不能夠單單由viewmodel層來處理。
所以說,viewmodel massive化的問題,需要考慮到與model層更好的解耦。

Thinking

結(jié)合上圖MVVM的定義,viewmodel與view層的關(guān)系,是通過狀態(tài)量的綁定,實現(xiàn)data和action的binding;viewmodel與model層的關(guān)系,是更新和監(jiān)聽。
如果viewmodel不直接處理model的獲取和轉(zhuǎn)化,而是將復(fù)雜的model處理獨立出去,然后采取類似viewmodel與view層binding的方式,是否可以實現(xiàn)viewmodel與model的更進(jìn)一步解耦?

Solution

實現(xiàn)viewmodel與model進(jìn)一步解耦,一個方案是,在中間架設(shè)datacontroller層。如圖:


屏幕快照 2020-04-14 上午10.31.15.png
  • viewmodel擁有datacontroller,通過對datacontroller的data binding,監(jiān)聽處理過的data,并將data處理為view層頁面量;
  • datacontroller擁有model,通過接收viewmodel發(fā)出的action,對model進(jìn)行update,同時監(jiān)聽model數(shù)據(jù)變化,對model數(shù)據(jù)進(jìn)行維護(hù)、轉(zhuǎn)化和處理;
  • view層擁有viewmodel,通過對viewmodel的binding,完成view層頁面量的刷新。
notice
  • viewmodel與datacontroller需有明確的分工。datacontroller的架設(shè),是為了解耦model層數(shù)據(jù)處理邏輯,是以model層業(yè)務(wù)功能為導(dǎo)向的,viewmodel中涉及view層數(shù)據(jù)的處理,不應(yīng)歸并到datacontroller來處理,而是viewmodel層配合datacontroller來處理數(shù)據(jù)。
  • viewmodel和datacontroller雖是擁有關(guān)系,但并非強(qiáng)關(guān)聯(lián)。datacontroller同樣可以被其他viewmodel使用,是獨立的數(shù)據(jù)處理組件。
  • 理解幾個data:viewmodel里的data,是頁面狀態(tài),面向頁面顯示的數(shù)據(jù);datacontroller里的data,是model數(shù)據(jù)經(jīng)過處理后的,面向業(yè)務(wù)的數(shù)據(jù);model里的data,是面向接口的數(shù)據(jù)層數(shù)據(jù)。
scene

以行情類APP中的個股詳情界面為例。個股詳情界面,包含股票的盤口信息,分時走勢圖,K線圖,成交明細(xì),買賣五檔等多個功能,這些數(shù)據(jù)的處理是非常復(fù)雜的。同一個功能的數(shù)據(jù),可能需要多個接口返回進(jìn)行拼裝。以K線圖為例,會要求歷史數(shù)據(jù)和當(dāng)日數(shù)據(jù)拼裝,并通過TCP實時接收服務(wù)器推送的最新一根數(shù)據(jù)。
考察此時datacontroller,需要完成以下幾個功能:

  • 多個接口的請求管理。歷史數(shù)據(jù)接口、當(dāng)日數(shù)據(jù)接口,以及服務(wù)器主動推送。
  • session管理。管理TCP推送,以及如果推送斷掉后的主動定時刷新。
  • model層數(shù)據(jù)處理。將各個接口返回數(shù)據(jù),轉(zhuǎn)化為業(yè)務(wù)需求數(shù)據(jù),例如K線數(shù)據(jù)拼裝、校準(zhǔn)、容錯。
  • 數(shù)據(jù)源切換。行情數(shù)據(jù)服務(wù)可能存在多個行情源,例如普通行情服務(wù)和level2服務(wù),行情源不同。需要datacontroller完成數(shù)據(jù)源切換,以及對應(yīng)數(shù)據(jù)model的轉(zhuǎn)換。輸出到viewmodel層的data保持統(tǒng)一。

從以上場景可看出,如果沒有datacontroller層,大量數(shù)據(jù)處理會耦合到viewmodel,一方面造成viewmodel的難以維護(hù),另一方面很多處理邏輯是可獨立可復(fù)用可單元測試的。

discussion

  1. 結(jié)合flux(react)的數(shù)據(jù)驅(qū)動模式
    datacontroller層的架設(shè),實際上也是數(shù)據(jù)驅(qū)動的一種實踐。viewmodel通過監(jiān)聽datacontroller,完成數(shù)據(jù)驅(qū)動,最終更新頁面狀態(tài)。
    更進(jìn)一步,可以嘗試結(jié)合flux(react)思想,設(shè)計datacontroller的具體實現(xiàn)。目前我的項目中,通過將flux思想引入datacontroller層,將各個接口實現(xiàn)轉(zhuǎn)換為對應(yīng)的action和reducer,采用組合的設(shè)計模式,自由組合各接口調(diào)用。接口返回的數(shù)據(jù),區(qū)分為業(yè)務(wù)state,viewmodel通過監(jiān)聽這些state,完成數(shù)據(jù)層的監(jiān)聽。
    react是前端開發(fā)的主流框架之一,然而對APP開發(fā)來說,由于view更新機(jī)制的不同,react state更新的方式并不能很好的體現(xiàn)APP開發(fā)的性能。但在數(shù)據(jù)層,react單向數(shù)據(jù)流的思想還是值得借鑒,特別是對于業(yè)務(wù)數(shù)據(jù)復(fù)雜的功能,能夠較好地管理數(shù)據(jù)更新。
  2. datacontroller與viewmodel同級的設(shè)計
    很早之前有一種MVVM設(shè)計,datacontroller層與viewmodel層同級,同為viewcontroller擁有。如下圖:


    1452138195768694.png

這種設(shè)計更體現(xiàn)出datacontroller層的獨立性。但正如作者所說,頻繁的在 DC-VC-VM 里來回傳遞信息,會造成了大量膠水代碼。且datacontroller直接暴露到viewcontroller,不利于view層與model層解耦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容