一、mvp介紹
随着ui建立技術的功能日益增強,ui層也履行着越來越多的職責。為了更好地細分視圖(view)與模型(model)的功能,讓view專注于處理資料的可視化以及與使用者的互動,同時讓model隻關系資料的處理,基于mvc概念的mvp(model-view-presenter)模式應運而生。
在mvp模式裡通常包含4個要素:
(1)view:負責繪制ui元素、與使用者進行互動(在android中展現為activity);
(2)view interface:需要view實作的接口,view通過view interface與presenter進行互動,降低耦合,友善進行單元測試;
(3)model:負責存儲、檢索、操縱資料(有時也實作一個model interface用來降低耦合);
(4)presenter:作為view與model互動的中間紐帶,處理與使用者互動的負責邏輯。
(原文位址:)
二、為什麼使用mvp模式
在android開發中,activity并不是一個标準的mvc模式中的controller,它的首要職責是加載應用的布局和初始化使用者界面,并接受并處理來自使用者的操作請求,進而作出響應。随着界面及其邏輯的複雜度不斷提升,activity類的職責不斷增加,以緻變得龐大臃腫。當我們将其中複雜的邏輯處理移至另外的一個類(presneter)中時,activity其實就是mvp模式中view,它負責ui元素的初始化,建立ui元素與presenter的關聯(listener之類),同時自己也會處理一些簡單的邏輯(複雜的邏輯交由presenter處理).
另外,回想一下你在開發android應用時是如何對代碼邏輯進行單元測試的?是否每次都要将應用部署到android模拟器或真機上,然後通過模拟使用者操作進行測試?然而由于android平台的特性,每次部署都耗費了大量的時間,這直接導緻開發效率的降低。而在mvp模式中,處理複雜邏輯的presenter是通過interface與view(activity)進行互動的,這說明了什麼?說明我們可以通過自定義類實作這個interface來模拟activity的行為對presenter進行單元測試,省去了大量的部署及測試的時間。
三、mvp與mvc的異同
mvc模式與mvp模式都作為用來分離ui層與業務層的一種開發模式被應用了很多年。在我們選擇一種開發模式時,首先需要了解一下這種模式的利弊:
無論mvc或是mvp模式都不可避免地存在一個弊端:
額外的代碼複雜度及學習成本。
這就導緻了這兩種開發模式也許并不是很小型應用。
但比起他們的優點,這點弊端基本可以忽略了:
(1)降低耦合度
(2)子產品職責劃分明顯
(3)利于測試驅動開發
(4)代碼複用
(5)隐藏資料
(6)代碼靈活性
對于mvp與mvc這兩種模式,它們之間也有很大的差異。有一些程式員選擇不使用任何一種模式,有一部分原因也許就是不能區分這兩種模式差異。以下是這兩種模式之間最關鍵的差異:
(參考文章:http://www.infragistics.com/community/blogs/todd_snyder/archive/2007/10/17/mvc-or-mvp-pattern-whats-the-difference.aspx)
mvp模式:
view不直接與model互動,而是通過與presenter互動來與model間接互動
presenter與view的互動是通過接口來進行的,更有利于添加單元測試
通常view與presenter是一對一的,但複雜的view可能綁定多個presenter來處理邏輯
mvc模式:
view可以與model直接互動
controller是基于行為的,并且可以被多個view共享
可以負責決定顯示哪個view
四、利用mvp進行android開發的例子
說了這麼多理論,現在輪到實踐了。
現在我們來實作這樣一個android上的demo(如圖):可以從edittext讀取使用者資訊并存取,也可以根據id來從背景讀出使用者資訊并顯示。
頁面布局很簡單,就不介紹了。下面根據mvp原則來進行編碼:
先來看看java檔案的目錄結構:
可以發現,presenter與model、view都是通過接口來進行互動的,既降低耦合也友善進行單元測試。
(1)首先我們需要一個userbean,用來儲存使用者資訊
(2)再來看看view接口:
根據需求可知,view可以對id、firstname、lastname這三個edittext進行讀操作,對firstname和lastname進行寫操作,由此定義iuserview接口:
(3)model接口:
同樣,model也需要對這三個字段進行讀寫操作,并存儲在某個載體内(這不是我們所關心的,可以存在記憶體、檔案、資料庫或者遠端伺服器,但對于presenter及view無影響),定義iusermodel接口:
(4)presenter:
至此,presenter就能通過接口與view及model進行互動了:
(5)useractivity:
useractivity實作了iuserview及view.onclicklistener接口,同時有一個userpresenter成員變量:
重寫了onclick方法:
可以看到,view隻負責處理與使用者進行互動,并把資料相關的邏輯操作都扔給了presenter去做。而presenter調用model處理完資料之後,再通過iuserview更新view顯示的資訊。
view剩下的方法及usermodel類不是我們所關心重點,如果有興趣可以在源碼中檢視。