1. 程式人生 > >細數android中MVP的“七宗罪”

細數android中MVP的“七宗罪”

前言

我們都知道,MVP是在MVC的基礎上做了一次升級,相比MVC,MVP中P層與V層隔離,V層只負責UI,業務邏輯由抽象出來的P層負責,真正意義上的隔離View的細節和複雜性的模式.......

好了好了,上面是網上MVP“鼓吹”的基本套路。“欲想讓其滅亡,必先使其膨脹”今天,反其道而行之,我們來羅列MVP的“七宗罪”

 

MVP的“七宗罪”

有一定經驗的工程師都知道,我們的java有六大基本原則,我們在程式設計的時候,應該儘量去遵循面向物件思想,遵循六大基本原則。而有時候,為了“合理”,我們會多繞很多“彎路”,比如要實現降低類間的耦合,不得已我們會寫出很多介面,這就造成了程式碼膨脹。耦合度與程式碼量之間,我們常常要做到取捨,沒有絕對的合理,只有相對的優化。MVP在追求它的自身理念的同時,也“不小心”違背了部分原則。

 

在開頭,先簡單來看看MVP的缺點

1.粒度不好控制,控制不好就需要寫過多的類和介面
2.如要重用presenter可能會實現過多不需要的介面
3.Presenter和View通過介面通訊太繁瑣,一旦View層需要的資料變化,那麼對應的介面就需要更改

 

違背開閉原則

我認為MVP設計的初衷是MVP三層分別用中介軟體銜接,三者可分由不同開發者開發,相互間實現無縫銜接。在MVP中,只有P層負責邏輯,具有獨立意志與決定權,是三層的主導,而V與M都只是工具,,V與M層的替換應該是得非常簡單。

可是,在實際中,V層與P層依賴性太強,V確實與M分開了,可是當我們業務涉及了視覺互動,UI邏輯要修改時,V與P相牽連,都要配合做改動,這樣就做不到我們上面初衷所設想的,P層編寫者要不斷被不是本質工作的任務牽連,著違背了開放封閉原則。形式上解耦,但是職責分工還是耦合。

 

違背單一職責原則(可解決)

在專案中,如果有fragment,我們經常把fragment作為V層,為了降低V與P的耦合,會在其主activity中去例項化P層的介面,這裡,我們是不把activity當初V層,而實際上,activity就應該是V層的一部分,如果把它當做V層,那V層持有P層的引用,這違背了單一職責原則。實際上,藉助其他工具庫是可以解決這個問題的。用Dagger2,實現“依賴注入,控制反轉”,不由呼叫者決定呼叫誰,把控制的主導權交給被注入者來決定,這就符合了單一職責原則,V層專心UI工作,如果要替換被注入的類,由注入者來改,呼叫者是感知不到的變化,不改動程式碼,從而減低耦合。實際上,解決方法已經在上文給出了。

違背迪米特原則

迪米特也就最少知道原則,這部分與上面開閉原則比較像,不做展開(像指定是導致違背原因相像,而不是原則本身像)

 

違背介面隔離原則(可解決,比較麻煩)

由回到了我們上面的問題,MVP中,一大難題是如何控制好P層介面的粒度,如果粒度太小,那麼一旦業務多起來,我們的P層會非常臃腫。而如果粒度太小,那麼我們一個P層確實可以達到複用,可卻導致了我們不同需求的V層複用同一個P層介面時,要實現好多我們不需要的方法,這就是非常典型的違背了介面隔離,介面的實現類不應該實現沒有的方法。

如果把控好P層的粒度可以解決這個問題,不過,在專案一開始就能把控好我們的業務,這要求對業務及程式碼的掌控能力比較強,這是比較考驗經驗的,所以解決其來也不簡單。而且,我認為介面的一個好處是可以在一開始對該介面的實現類有一個大體的把控,起到了引導的作用。如果這樣看,那麼多寫介面未必是壞事,相反,為了避免P層膨脹,強行讓介面可複用,這就導致介面成為了程式碼的“束縛”。

 

違背依賴倒置與里氏替換原則

??!!

我數著基本原則也就六個,這是全都搞砸了??!!

好啦好啦,這兩個純屬開玩笑的,再違背下去,MVP都快要“十惡不赦”了。

那麼有人會說,你這不是“槓精”嗎,欲加之罪何患無辭!照你這麼說,MVP怎麼可能會有人用,這不是吹毛求疵嗎?

非也非也,MVP能做到成為主流的框架,自然有他的很多優勢。這裡我強行“擡槓”,不是說它不好,只是在強調它不一定就合適。

我所想表達的是,在開發中,我們選擇主流的不一定就是對的,比如我們選擇圖片載入框架,我們看到Glide封裝的最完善易用,我們就貿然使用了它,卻沒考慮到他的庫非常佔記憶體,其他庫也許更合適。

 

本文意義所在

在開發過程中,最難的並不是完成應用的開發工作,而是在後續擴充套件維護的過程,如何讓應用系統能擁抱不斷的變化迭代,在不破壞原有穩定性的基礎上提高可擴充套件性,達到高內聚,低耦合。這是為什麼要追求穩定的系統框架設計。

回到主題,上面列舉其違背原則,是想說,我們的MVP在實際不同的專案中,並不是一成不變的,根據不同的情況我們可能會在MVP的基礎上做改動。比如某公司由於人員分配,V層與P層有不同團隊人員並行開發,那麼為了做到彼此並行,那麼我們就會像我上面強行“擡槓”那樣,要求其解決“介面隔離,單一職責原則的問題”,解決粒度的問題。具體做法可能會是在MVP基礎上,在V與P之間加一層路由,實現解耦,也可以是通過使用LiveData+ViewModel,甚至使用EventBus來實現各層之間的通訊。不同情況不同做法,程式設計是沒有一套絕對的標準,這些都是要根據需求,根據人員配置,選擇合適的做法,並接受其帶來的弊端。

 

 

我們的MVP在大的專案中的使用相對還是比較得心應手的,但是,如果你的專案不大,並且由一個人開發。你強行使用MVP,那麼你專案的前期可能得重複寫好多介面,這很讓人頭大。

相比MVP,MVVM在某些方面更加友好,其實好多有經驗的工程師,更傾向於在MVP與MVVM之間取得一個折中,一種比較優雅的寫法是MVP+LiveData+ModeView+LifeCycle+Dagger2。

有的人看到這裡已經坐不住了,別急,都看到這了,那我就不往下講了。。。。。。。。。。。

 

 

 

 

哈哈,開玩笑的。關於架構的選擇與優化,我會在後面搞一個比較詳細的系列來與大家一起交流學習。涉及了MVVM,架構元件,以及對於MVVM與MVP的優化。本文僅作為該系列的引子。旨在追求一套適合個人的框架。

謝謝你的閱讀,如果有收穫,不要吝惜你的點贊。如果有偏頗,請你指出,相互學習進步。謝謝你!