本文由業(yè)松所寫,轉(zhuǎn)載請注明作者。
先上個鏈接吧,谷歌官方github的Android架構(gòu)demo,里面有各種各樣的MVP、MVVM架構(gòu),可以clone下來自己新建項目的時候作參考。clone后需要切換branch才能看到其他架構(gòu)的代碼。
今年MVC、MVP、MVVM都有寫,其中MVVM以前沒接觸過,現(xiàn)在終于可以談?wù)勥@三種架構(gòu)的使用感受了。由于今年寫的Android項目都是商業(yè)的,沒寫個人項目,代碼貼不了(可以說純干聊,無干貨- -)。
子虛烏有的MVC(Model-View-Controller)
為什么說Android MVC架構(gòu)子虛烏有?MVC分層概念是在Java后臺Spring框架里拿過來的。人家的Controller和View層代碼確實是分離的。Android里面哪里分了,對此我斗膽做個猜測:在發(fā)明Android-MVP架構(gòu)的時候,大家不知道怎么稱呼原始的Android架構(gòu),于是強(qiáng)行從Spring那里拿了個MVC的名字把它和MVP區(qū)分開來。
Controller層的本意是處理事件的分發(fā)和響應(yīng),把Activity看作Controller層也不是不可以,但是既然View和Controller并沒有分層,沒必要牽強(qiáng)附會到MVC上去。
所以所謂的MVC在Android里就是沒有分層架構(gòu)的意思。沒有分層的架構(gòu)是不是就一定不好呢?當(dāng)然不是,別說小型應(yīng)用,就是谷歌自己寫的應(yīng)用也有好幾千行代碼一個Activity好幾千行代碼擼到底的呢(想找個例子來著,發(fā)現(xiàn)最新版本的aosp里Activity和Fragment代碼都精簡了不少)。
在代碼領(lǐng)域很多事情不是非此即彼,我見過不少商業(yè)項目有著各種架構(gòu)、設(shè)計模式還有封裝好的基類,最后Presenter里就幾行代碼甚至一行代碼都沒有。因此對于小項目,Activity里的代碼不重的話,沒必要各種分層。對于可能會寫成大項目的項目,也可以先不分層,后續(xù)該重構(gòu)的時候再重構(gòu)。真的要一個Activity幾千行的話肯定是不建議的,閱讀性太差,定位、修改起來也十分困難。
商業(yè)項目廣泛使用的MVP(Model-View-Presenter)
MVP架構(gòu)在Android領(lǐng)域可謂十分成熟,我見過的商業(yè)項目很多都喜歡用MVP架構(gòu)。好處自然不用多說,把與UI無關(guān)的邏輯代碼全部抽出來放到Presenter層里,用接口明確定義好View層和Presenter層的功能。這樣的話架構(gòu)層次清晰,閱讀和修改起來要容易得多。
不過使用MVP架構(gòu)的項目往往會有過度封裝的傾向。基本上都會封裝有BaseActivity、BaseFragment、BasePresenter,BaseView、BaseModel等等。封裝可以讓我們更多地復(fù)用代碼,少寫重復(fù)代碼。但是封裝是不是百利而無一害呢?當(dāng)然不是,封裝有時候會犧牲代碼的靈活性。比如在基類里定義了太多類的行為,子類想要修改就只能復(fù)寫。但是可能一個地方例外,所以地方都變得不一樣,封裝的太死的話很多地方都要重寫。因此基類的東西應(yīng)該只有確定所有子類都一致的東西,不要試圖把所有的東西都塞到基類里。我當(dāng)時所在的一個項目用的mvp?dagger架構(gòu),新建一個Fragment大概要添加/修改七八個類,不得不說真的挺費勁的。
毫無疑問,MVP給Android帶來了代碼分層的概念,確實是一個很好的實踐。但是在使用MVP之前先考慮一下自己能不能接受一個頁面至少要寫四五個類- -
最“流行”的MVVM(Model-View-ViewModel)
為啥流行加了雙引號呢,因為在Android領(lǐng)域還是MVP最流行,而在Javascript前端領(lǐng)域,Angular、Vue、React都是MVVM架構(gòu)。所以MVVM是真的火到爆炸。至于為什么Android MVVM還不是很流行呢(起碼我身邊很多同行都沒用過,我也是今年才真正用過)?之前和微信群里的一個網(wǎng)友討論過,我覺得他說的很有道理:前幾年Android開發(fā)火熱的時候MVP架構(gòu)應(yīng)運而生,人人面試都要談MVP。而今更新一代的MVVM架構(gòu)出來后,Android開發(fā)市場早已冷卻,大家沒有動力去切換新的設(shè)計模式,畢竟哪怕啥架構(gòu)模式也沒有不也一樣能開發(fā)大型項目么?
MVP和MVVM有啥區(qū)別呢?我也看過很多文章,不過talk is cheap,看再多還是要真正去實踐才能感受MVVM架構(gòu)的好用之處,也明白了為什么三大JS前端框架都用這種架構(gòu)。
MVP和MVVM區(qū)別就是P和VM區(qū)別。Presenter層是把UI無關(guān)的邏輯自己處理掉,最后把處理完的數(shù)據(jù)傳輸給View層展示;ViewModel是把Model和View層關(guān)聯(lián)起來的一個中間層,讓View層可以響應(yīng)式地展示數(shù)據(jù)。在我看來,VM的核心思想就是UI回調(diào)。View層通過ViewModel可以直接動態(tài)地展示數(shù)據(jù),我們不需要在數(shù)據(jù)改變時去回調(diào)UI,這樣可以省去非常非常多的UI代碼,怪不得前端都喜歡MVVM。
Android MVVM的實現(xiàn)方式主要有兩種,一種是給數(shù)據(jù)加監(jiān)聽,比如使用LiveData,在數(shù)據(jù)變化時執(zhí)行監(jiān)聽的回調(diào),這樣就不需要每次改變數(shù)據(jù)后再手動地修改UI。第二種就是[DataBinding]{https://developer.android.com/topic/libraries/data-binding/}框架了。在layout xml里面定義Observable數(shù)據(jù),然后直接把數(shù)據(jù)塞給控件。通常我們會把要展示的最終數(shù)據(jù)封裝到ViewModel層代碼里。而且在xml里也能對數(shù)據(jù)進(jìn)行簡單的操作,具體數(shù)據(jù)操作大家在這里查到。
MVP并沒有真正減少代碼,只是把代碼做了分層。而MVVM不但讓代碼分層的更加干凈,還減少了大量的UI回調(diào)代碼。因此用過MVVM之后我就愛上了它,相信你也一樣!
關(guān)于Model層
從寫MVP代碼開始我就在想,Model層到底是個啥?很多人把Model層翻譯為數(shù)據(jù)層,可是Model是模型的意思啊。Model是不是只包括Model類,還是包含數(shù)據(jù)增刪改查所有代碼,我一直在想這個問題。而且我問過不少人看過不少文章,各種看法都有。
在上面的googlesamples,很多架構(gòu)的M層是包含數(shù)據(jù)的獲取的,并且會封裝到XXXRepository類里。這樣做的好處就是保證數(shù)據(jù)來源的唯一性(前端數(shù)據(jù)層框架Redux三大原則第一條就是Single source of truth)。而在SpringMVC里面,pojo數(shù)據(jù)的增刪改查被封裝到dao層,業(yè)務(wù)處理會封裝到service層。因此大型架構(gòu)的數(shù)據(jù)的操作基本上都會進(jìn)行封裝,這點沒有疑問。至于這些repository、dao、service層屬于Model層還是Presenter層還是另外一個層面,可以看看Wiki上關(guān)于MVC的定義:
The model is the central component of the pattern. It is the application's dynamic data structure, independent of the user interface.It directly manages the data, logic and rules of the application.
從這段話可以看出來dao層,repository層確實屬于Model層,至于更進(jìn)一步的業(yè)務(wù)處理,則不屬于Model層(比如在MVP里就是P層)。
最后歡迎大家多多交流,不吝指點。