前言
近期一直在看設計模式相關的資料,每逢結尾都會介紹到 MVC 模式,而最近比較火的卻是 MVP 和 MVVM ,更有甚者,將 MVP 和 MVVM 結合起來形成了 MVPVM ,大神的造詣總是讓俺望其項背,下面就結合自己的學習,淺析 MVP。
從哪里開始學習呢?當然是從 Google 自身開始咯,Google 推出了自己的官方 MVP 架構例子。源碼地址
相關翻譯
今天就主要來看看官方寫的最基礎的 MVP 的例子 todo-mvp。本文不打算講解里面代碼的具體實現,只是從宏觀角度看一下,Google是如何實現 MVP 模式的,細節(jié)需要自己慢慢體會,每個人的體會都會不一樣的。(里面還涉及到了測試相關的東西)
剖析
Step One
首先從 Github 上 clone 下來,然后本地運行起來,效果如下

這是一個簡版的便簽,相關數據存儲在本地數據庫中。知道這個 App 是干嘛的,對下面分析相關代碼就好理解了。
Step Two
看代碼,找關系,官方的代碼結構如下

看目錄
- addetitask:添加/修改任務功能
- statistics:分析功能(位于側邊欄上)
- taskdetail:查看任務詳情
- tasks:首頁界面,展示任務列表
- data:數據操作相關
- util:工具類相關
通過目錄,這個 App 的相關操作也就一目了然了,接下來就針對 task 目錄下的代碼進行分析,看看是如何體現 MVP 思想的。
Step Three
分析前,先認識一下 MVP ,至少了解一下代表的含義
MVP (Model-View-Presenter) 該模式包含以下幾個方面
- View:負責繪制 UI 元素、與用戶進行交互(Activity/Fragment);
- View interface:需要 View 實現的接口,View 通過 View interface 與 Presenter 進行交互,降低耦合,方便進行單元測試;
- Model:負責存儲、檢索、操縱數據(有時也實現一個Model interface 用來降低耦合);
- Presenter:作為 View 與 Model 交互的中間紐帶,處理與用戶交互的負責邏輯。
先掌握上面的基礎概念就可以,下面進入正題
Step Four
task 目錄下包含了以下幾個文件
- ScrollChildSwipeRefreshLayout:自定義控件,擴展了 SwipeRefreshLayout
- TasksActivity:程序入口
- TasksContract:關聯(lián)了 View 和 Presenter,是個接口
- TasksFilterType:是個枚舉類,里面定義了 Tasks 列表的狀態(tài);
- TasksFragment:展示 Tasks 列表等相關操作的 Fragment;
- TasksPresenter: Presenter,負責關聯(lián) View 和 Model
它們的關系用類圖來表示,如下圖所示
其中數據類的相關 java 類簡化表示了,詳細的自行查閱 Github 上的內容
從上面可以看到,Google 首先定義了兩個接口文件 BaseView 和 BasePresenter,然后又通過 接口 TasksContract 進行關聯(lián),所有用到上面兩個接口的都是通過 TasksContract 進行管理。
看上面的圖,好像有點繁雜,眼花繚亂的感覺,那就先搬一張 MVP 模式基本的類圖,如下
那么結合上圖,怎么根據上面進行劃分呢,其實非常容易,如下

上面標的還不算特別好,其中 BaseView 也屬于 View 里面,BasePresenter 屬于 Presenter 范疇
如果大家仔細看的話,就會發(fā)現,View 和 Model 直接是沒有任何關聯(lián)的哦,而 Presenter 和 Model 和 View 都是有關聯(lián)的,現在在和上面標準的類圖進行對比,是不是就一目了然啦。如果大家對里面的代碼細節(jié)感興趣,請自行查閱源碼哦。
對了,說一點,里面的 TasksActivity 的作用就是將 Presenter 和 TasksFragment 關聯(lián)起來(不貼點代碼好像也不行了)
TasksFragment tasksFragment =
(TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
if (tasksFragment == null) {
// Create the fragment
tasksFragment = TasksFragment.newInstance();
ActivityUtils.addFragmentToActivity(
getSupportFragmentManager(), tasksFragment, R.id.contentFrame);
}
// Create the presenter
mTasksPresenter = new TasksPresenter(
Injection.provideTasksRepository(getApplicationContext()), tasksFragment);
// Load previously saved state, if available.
if (savedInstanceState != null) {
TasksFilterType currentFiltering =
(TasksFilterType) savedInstanceState.getSerializable(CURRENT_FILTERING_KEY);
mTasksPresenter.setFiltering(currentFiltering);
}
Step Five
再來審視一下 MVP
- M:Model,數據相關,主要就是提供數據的存取功能,像一個數據倉庫。Presenter 需要通過 Model 層存、取數據。
- V:View,用戶界面,也就是Activity、Fragment、View控件等,它持有 Presenter 的一個成員變量。通常 View 需要實現一個邏輯接口(示例就是這樣做的),將 View 上的操作會轉交 Presenter 來年實現。最后,Presenter 調用 View 的邏輯接口將結果返回給 View 元素。
- P:Presenter,交互中間人。溝通 Model 和 View 的橋梁,將 Model 和 View 之間的關聯(lián)斬斷掉,改為 Presenter 進行聯(lián)絡。這也是和 MVC 模式最大的不同。
MVP 的優(yōu)點
- 看類圖就知道,首先就是分離了 View 和 Model,降低了耦合
- 易于維護、測試,一目了然,接口的存在,大大降低了測試的復雜度
- 代碼的可閱性就變的容易了
- 類型的職責明確,各司其職,應用 MVP 時,會感覺到,結構清晰明了,爽
說完優(yōu)點,肯定有缺點的,誰讓沒有一個模式都是金光閃閃,毫無缺點的。
- Presenter 負責溝通 Model 和 View ,當然不可避免的就會“臃腫”起來
- 有 View 的存在,就會有 Presenter 的存在,而在實際項目中,一個界面往往有很多的 View 構成,那么想想也是很“激動”的
最后
每個模式的出現,都會解決其他模式的缺點,卻又不可避免的帶來自身的缺點,然后等著下一模式的出現來解決上一模式的缺點,周而復始。也正是這樣的循環(huán),讓我們不斷的向更好的方向進步,例如: MVVM 的出現。
想要深入學習,查看具體實現方式,請自行下載相關代碼進行研究。
參考資料
Android開發(fā)藝術探索[M]. 電子工業(yè)出版社, 2015.487-494