Android開發中的MVP架構詳解
最近越來越多的人開始談論架構。我周圍的同事和工程師也是如此。儘管我還不是特別深入理解MVP和DDD,但是我們的新專案還是決定通過MVP來構建。
這篇文章是我通過研究和學習各種文章以及專題討論所總結出來的,它包括以下幾點:
- 為什麼越來越多的人開始關注架構?
- 首先,MVP是什麼?
- 哪種架構才是最好的,MVC,MVVM還是MVP?
- MVP的利與弊
- Show me the code!!!程式碼展示
不幸的,這篇文章將不包括:
- 詳細生動的程式碼示例
- 如何編寫測試程式碼
最後,我將告訴你如何更進一步學習這些專題。
順便提一下,我於上週在當地的一個研討會上對MVP架構進行了相關演講。這篇文章與當時的演講內容相差無幾。
(譯者注:閱讀更多請點選原作者PPT)
介紹~Activity是上帝類~
首先,讓我們思考一下為什麼在Android開發中如此迫切地需要一個清晰的軟體架構。
該段摘自“程式碼大全第二版”:
避免建立神類。避免建立無所不知,無所不能的上帝類。如果一個類需要花費時間從其他類中通過Get()和Set()檢索資料(也就是說,需要深入業務並且告訴它們如何去做),所以是否應該把這些功能函式更好的組織到其它類而不是上帝類中。(Riel 1996)
上帝類的維護成本很高,你很難理解正在進行的操作,並且難以測試和擴充套件,這就是為什麼要避免建立上帝類的黃金法則。
然而,在Android開發中,如果你不考慮架構的話,Activity類往往會越來越大。這是因為,在Android中,允許View和其它執行緒共存於Activity內。其實最大的問題莫過於在Activity中同時存在業務邏輯和UI邏輯。這會增加測試和維護的成本。
這是為什麼需要清晰架構的原因之一。不僅會造成Activity的臃腫,還會引起其他問題,如使Activity和Fragment的生命週期變複雜,以及資料繫結等。
什麼是MVP?
MVP代表Model,View和Presenter。
- View層負責處理使用者事件和檢視部分的展示。在Android中,它可能是Activity或者Fragment類。
- Model層負責訪問資料。資料可以是遠端的Server API,本地資料庫或者SharedPreference等。
- Presenter層是連線(或適配)View和Model的橋樑。
下圖是基於MVP架構的模式之一。View是UI執行緒。Presenter是View與Model之間的介面卡。UseCase或者Domain在Model層中,負責從實體獲取或載入資料。依賴規則如下:
關鍵是,高層介面不知道底層介面的細節,或者更準確地說,高層介面不能,不應該,並且必須不瞭解底層介面的細節,是(面向)抽象的,並且是細節隱藏的。
依賴規則?
Uncle Bob的“The Clean Architecture”描述了依賴的規則是什麼。
同心圓將軟體劃分為不同的區域,一般的,隨著層級的深入,軟體的等級也就越高。外圓是實現機制,內圓是核心策略。
這是上面片文章的摘要:
Entities:
- 可以是一個持有方法函式的物件
- 可以是一組資料結構或方法函式
- 它並不重要,能在專案中被不同應用程式使用即可
Use Cases
- 包含特定於應用程式的業務規則
- 精心編排流入Entity或從Entity流出的資料
- 指揮Entity直接使用專案範圍內的業務規則,從而實現Use Case的目標
Presenters,,Controllers
- 將Use Case和Entity中的資料轉換成格式最方便的資料
- 外部系統,如資料庫或網頁能夠方便的使用這些資料
- 完全包含GUI的MVC架構
External Interfaces, UI, DB
- 所有的細節所在
- 如資料庫細節,Web框架細節,等等
MVC,MVP還是MVVM?
那麼,哪一個才是最好的呢?哪一個比其他的更優秀呢?我能只選擇一個嗎?
答案是,NO。
這些模式的動機都是一樣的。那就是如何避免複雜混亂的程式碼,讓執行單元測試變得容易,創造高質量應用程式。就這樣。
當然,遠不止這三種架構模式。而且任何一種模式都不可能是銀彈,他們只是架構模式之一,不是解決問題的唯一途徑。這些只是方法、手段而不是目的、目標。
利與弊
OK,讓我們回到MVP架構上。剛剛我們瞭解了什麼是MVP,討論了MVP以及其它熱門架構,並且介紹了MVC,MVP和MVVM三者間的不同。這是關於MVP架構利與弊的總結:
**利
- 可測試(TDD)
- 可維護(程式碼複用)
- 容易Reviewe
- 資訊隱蔽
**弊
- 冗餘的,尤其是小型App開發
- (有可能)額外的學習曲線
- 開始編寫程式碼之前需要時間成本(但是我敢打賭,設計架構是所有專案開發所必需的)
Show me the code!!!
這裡僅展示了MVP模式的一小段結構。如果你想了解更多專案或生動的程式碼示例,請參考文章末尾的“連結和資源”。那裡有非常豐富和設計巧妙的示例,基本都託管在Github上,以便你能clone,在裝置上執行,並瞭解工作原理。
首先,為每一個View定義介面。
/** * Interface classes for the Top view */ public interface TopView { /** * Initialize the view. * * e.g. the facade-pattern method for handling all Actionbar settings */ void initViews(); /** * Open {@link DatePickerDialog} */ void openDatePickerDialog(); /** * Start ListActivity */ void startListActivity(); }
讓我們重寫TopView類,要點如下:
- TopActivity只是負責處理事件監聽或者展示每個檢視元件
- 所有的業務邏輯必須委託給Presenter類
- 在MVP中,View和Presenter是一 一對應的(在MVVM中是一對多的)
public class TopActivity extends Activity implements TopView { // here we use ButterKnife to inject views /** * Calendar Title */ @Bind(R.id.calendar_title) TextView mCalendarTitle; private TopPresenter mTopPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_top); ButterKnife.bind(this); // Save TopPresenter instance in a meber variable field mTopPresenter = new TopPresenter(); mTopPresenter.onCreate(this); } /* * Overrides method from the {@link TopView} interfaces */ @Override public void initViews() { // Actionbar settins // set event listeners } @Override public void openDatePickerDialog() { DatePickerFragment.newInstance().show(getSupportFragmentManager(), DatePickerFragment.TAG); // do not write logic here... all logic must be passed to the Presenter mTopPresenter.updateCalendarDate(); } @Override public void startListActivity() { startActivity(new Intent(this, ListActivity.class)); } }
這是Presenter類,最重要的一點是Presenter僅僅是連線View與Model的適配橋樑。比如,TopUseCase#saveCalendarDate()
是對TopPresenter細節隱藏的,同樣對TopView也是如此。你不需要關心資料結構,也不需要關心業務邏輯是如何工作的。因此你可以對TopUseCase執行單元測試,因為業務邏輯與檢視層是分離的。
ublic class TopPresenter { @Nullable private TopView mView; private TopUseCase mUseCase; public TopPresenter() { mUseCase = new TopUseCase(); } public void onCreate(@NonNull TopView topView) { mView = topView; // here you call View's implemented methods mView.initViews(); } public void updateCalendarDate() { // do not forget to return if view instances is null if (mView == null) { return; } // here logic comes String dateToDisplay = mUseCase.getDateToDisplay(mContext.getResources()); mView.updateCalendarDate(dateToDisplay); // here you save date, and this logic is hidden in UseCase class mUseCase.saveCalendarDate(); } }
當然,儘管業務邏輯被實現在Activity類中,你依然可以執行單元測試,只不過這會耗費很多時間,而且有些複雜。可能需要更多的時間來執行App,相反,你本應該充分利用測試類庫的效能,如Robolectric。
總結
這裡沒有萬能藥,而且MVP也僅僅是解決方案之一,它可以與其他方法協同使用,同樣,也可以有選擇的用於不同專案。
連結和資源
The Clean Architecture(譯者注:清晰架構。譯文) – Uncle Bob
這篇文章由Uncle Bob撰寫,描述了依賴規則的樣子和它們之間的元件是如何工作的。我從一開始談論的那張圖表的靈感就來源於他的文章,雖然這篇文章不是針對Android開發的,但是同往常一樣,字裡行間蘊藏著很多精闢的道理,所以,必讀。
Architecting Android…The clean way? (譯者注:Android中的清晰架構。譯文)- Fernando Cejas
我認為這是在探索如何將MVP架構到Android開發專題中最著名,也是最受歡迎的部落格。我也是從他那篇簡單易讀,書寫良好的部落格中偶然發現“MVP”這個名詞的。他的示例程式碼託管在Github上,以便那些想要將MVP架構運用到正式App上的Android開發者clone到。
Android Architecture(譯者注:Android架構) – Thanos Karpouzis
一個在Android專案中運用MVC,MVP,MVVM的簡單指導。我從他的那篇普通卻不平凡的文章中學到了很多,尤其是MVC,MVP和MVVM之間的不同。
Software Design patterns on Android English(譯者注:Android開發中的軟體設計模式) – Pedro Vicente Gómez Sánchez
這是一個在Karumi工作的高階Android開發工程師所講的,他解釋了一些MVP架構中的設計模式(如,渲染模式,倉庫模式和命令模式)。如果你想深入理解MVC或者MVP,那這就使你要找的。
M — Model in MVC, MVP, MVVC in Android(譯者注:MVC,MVP,MVVC架構中Model層在Android中的定義) – Artem Zinnatullin
如果你不還了解Model層中的JSON與SQL,或者不能透徹理解Model層的影像模型,這篇文章將帶你進一步理解什麼是Model層以及為什麼Model層獨立於其他層。其中“Model layer is solution”部分很好的解釋瞭如何通過面向介面的方式編寫測試。
相關文章
- Android MVP 架構AndroidMVP架構
- iOS開發-MVP架構模式iOSMVP架構模式
- Android-MVP架構AndroidMVP架構
- MVP:有呼吸的Android架構MVPAndroid架構
- 聊聊Android開發中的MVP模式AndroidMVP模式
- Android架構系列-MVP架構的實際應用Android架構MVP
- android-MVP架構中Presenter的單元測試AndroidMVP架構
- Android應用中Clean架構使用詳解Android架構
- Android架構系列-基於MVP建立適合自己的架構Android架構MVP
- Facebook移動架構:Android Flux架構詳解架構AndroidUX
- Android 檢視架構詳解Android架構
- Android架構元件WorkManager詳解Android架構元件
- Android 架構選型 (MVP+DataBinding)Android架構MVP
- Android應用架構之MVP實現Android應用架構MVP
- Android從零開始(第三篇)MVP架構搭建AndroidMVP架構
- 開源專案Philm的MVP架構分析MVP架構
- Android MVP架構改造~如何重用頂層業務AndroidMVP架構
- 談談 Android MVP 架構 | 掘金技術徵文AndroidMVP架構
- Android 架構設計:MVC、MVP、MVVM和元件化Android架構MVCMVPMVVM元件化
- Android MVP架構(RxJava+SQLBrite+Retrofit+OkHttp+Glide)AndroidMVP架構RxJavaSQLHTTPIDE
- MVP應用架構模式MVP應用架構模式
- MVP架構設計 初探MVP架構
- Android系統架構詳解(2)--Android RuntimeAndroid架構
- Android架構系列-開發規範Android架構
- Android應用開發架構概述Android架構
- Android MVP架構(Volley+CursorLoader+ContentProvider)AndroidMVP架構IDE
- MVC、MVP、MVVM,談談我對Android應用架構的理解MVCMVPMVVMAndroid應用架構
- iOS架構詳解iOS架構
- android基於openfire+smack開發之【架構瞭解】AndroidMac架構
- Android開發為什麼要用MVP?AndroidMVP
- 【Android】一鍵生成MVP程式碼-DevMvp快速開發框架AndroidMVPdev框架
- 談談Android中的MVPAndroidMVP
- 系統開發中的B/S架構架構
- Google工程師多圖詳解Android架構Go工程師Android架構
- iOS 架構模式–解密 MVC,MVP,MVVM以及VIPER架構iOS架構模式解密MVCMVPMVVM
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝(一)Android架構MVP模式RxJava封裝
- Android MVP架構從入門到精通-真槍實彈AndroidMVP架構
- Android開發規範詳解Android