前言:
本篇關於MVP架構的學習是在查閱了很多資料整理出來。網上一些關於Android MVP的介紹都有點淺嘗輒止,一個登錄或者根據地區查詢天氣等的小Demo,沒有實際在項目中應用的示例,所以在用MVP做完一個小項目之後還是不敢在主項目中輕易嘗試。首先,主項目改動起來工作量很大,時間不允許;其次,知道自身對MVP理解還不夠,怕掉坑裏去;今天主要是想分享一下,本人對MVP的淺見,以及如何使用MVP模式搭建一個項目框架。後續在工作中學習到了有關於MVP模式的見解會繼續發表文章。
微軟公司對MVC和MVP模式的差異圖解:
我們模擬一個需求:首先我們要進入一個Splash界面,Splash界面中,有一個ProgressBar控件和TextView控件,我們判斷它是否有網絡連接,如果有的話就隱藏 ProgressBar和跳轉到MainActivity如果沒有網絡的話則顯示ProgressBar和TextView,TextView則提示用戶No internet。就這麼簡單的一個需求,我們看看如何用MVP模式做這個需求。
首先我們看下M層是如何接口寫的
優點:
1. 降低耦合度,實現了Model和View真正的完全分離,可以修改View而不影響Modle
2. 模塊職責劃分明顯,層次清晰(下面會介紹Bob大叔的Clean Architecture)
3. 隱藏數據
4. Presenter可以複用,一個Presenter可以用於多個View,而不需要更改Presenter的邏輯(當然是在View的改動不影響業務邏輯的前提下)
5. 利於測試驅動開發。以前的Android開發是難以進行單元測試的(雖然很多Android開發者都沒有寫過測試用例,但是隨着項目變得越來越複雜,沒有測試是很難保證軟件質量的;而且近幾年來Android上的測試框架已經有了長足的發展——開始寫測試用例吧),在使用MVP的項目中Presenter對View是通過接口進行,在對Presenter進行不依賴UI環境的單元測試的時候。可以通過Mock一個View對象,這個對象只需要實現了View的接口即可。然後依賴注入到Presenter中,單元測試的時候就可以完整的測試Presenter應用邏輯的正確性。
6. View可以進行組件化。在MVP當中,View不依賴Model。這樣就可以讓View從特定的業務場景中脫離出來,可以說View可以做到對業務完全無知。它只需要提供一系列接口提供給上層操作。這樣就可以做到高度可複用的View組件。
7. 代碼靈活性
缺點:
1. Presenter中除了應用邏輯以外,還有大量的View->Model,Model->View的手動同步邏輯,造成Presenter比較笨重,維護起來會比較困難。
2. 由於對視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會過於頻繁。
3. 如果Presenter過多地渲染了視圖,往往會使得它與特定的視圖的聯繫過於緊密。一旦視圖需要變更,那麼Presenter也需要變更了。
4. 額外的代碼複雜度及學習成本。
什麼是MVP
MVP,全稱 Model-View-Presenter
要說MVP那就不得不說一說它的前輩——MVC。
MVC(Model-View-Controller,模型-視圖-控制器)模式是80年代Smalltalk-80出現的一種軟件設計模式,後來得到了廣泛的應用,其主要目的在於促進應用中模型,視圖,控制器間的關注的清晰分離。MVP(Model-View-Presenter,模型-視圖-表示器)模式則是由IBM開發出來的一個針對C++和Java的編程模型,大概出現於2000年,是MVC模式的一個變種,主要用來隔離UI、UI邏輯和業務邏輯、數據。也就是說,MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示(一般可以理解爲Activity和Fragment)。
要說MVP那就不得不說一說它的前輩——MVC。
MVC(Model-View-Controller,模型-視圖-控制器)模式是80年代Smalltalk-80出現的一種軟件設計模式,後來得到了廣泛的應用,其主要目的在於促進應用中模型,視圖,控制器間的關注的清晰分離。MVP(Model-View-Presenter,模型-視圖-表示器)模式則是由IBM開發出來的一個針對C++和Java的編程模型,大概出現於2000年,是MVC模式的一個變種,主要用來隔離UI、UI邏輯和業務邏輯、數據。也就是說,MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示(一般可以理解爲Activity和Fragment)。
微軟公司對MVC和MVP模式的差異圖解:
大家會發現MVP與MVC最大的一個區別就是“Model與View層之間倒底該不該通信(甚至雙向通信)。我想這也是目前做這兩方面研究的專家所互相爭論的戰場。必定各有各的好處和因好處要付出的代價。起碼在MVP模式下的Presenter要擁有“絕對權力”。如果沒有它,MODEL與View就是兩個孤島,儘管各有各的地盤(完全解耦),但不會給企業帶來什麼有用的價值。
MVP案例分析:
這篇博客MVP模式在Android開發中的應用 的案例也很好理解,AndroidStudio版源碼下載:源碼。只是有一個問題,這樣會造成內存泄漏。優化後代碼下載:待續。。。
下面再舉一個例子:
待續。。。
一個MVP的項目,先從項目目錄結構上面來看
首先我們看下M層是如何接口寫的
package com.manning.androidhacks.hack020.presenter.model;
public interface IConnectionStatus {
boolean isOnline();
}
然後看看實現(我們主要是看MVP模式的使用,所以在此就不做網絡連接的檢查了,模擬一個狀態)package com.manning.androidhacks.hack020.presenter.model.impl;
import com.manning.androidhacks.hack020.presenter.model.IConnectionStatus;
public class ConnectionStatus implements IConnectionStatus {
@Override
public boolean isOnline() {
// TODO: Here we should place the code to check the connectivity.
return true;
}
}
然後我們在來看看V的接口package com.manning.androidhacks.hack020.view;
public interface ISplashView {
void showProgress();
void hideProgress();
void showNoInetErrorMsg();
void moveToMainView();
}
以及V的實現
package com.manning.androidhacks.hack020.view.impl;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.manning.androidhacks.hack020.R;
import com.manning.androidhacks.hack020.presenter.SplashPresenter;
import com.manning.androidhacks.hack020.view.ISplashView;
public class SplashActivity extends Activity implements ISplashView {
private TextView mTextView;
private ProgressBar mProgressBar;
private SplashPresenter mPresenter = new SplashPresenter();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
mPresenter.setView(this);
mTextView = (TextView) findViewById(R.id.splash_text);
mProgressBar = (ProgressBar) findViewById(R.id.splash_progress_bar);
}
@Override
protected void onResume() {
super.onResume();
mPresenter.didFinishLoading();
}
public void showProgress() {
mProgressBar.setVisibility(View.VISIBLE);
}
public void hideProgress() {
mProgressBar.setVisibility(View.INVISIBLE);
}
public void showNoInetErrorMsg() {
mTextView.setText("No internet");
}
@Override
public void moveToMainView() {
startActivity(new Intent(this, MainActivity.class));
}
}
最後我們來看看P層是如何控制他們的邏輯的:public class SplashPresenter {
private IConnectionStatus mConnectionStatus;
private ISplashView mView;
public SplashPresenter() {
this(new ConnectionStatus());
}
public SplashPresenter(IConnectionStatus connectionStatus) {
mConnectionStatus = connectionStatus;
}
public void setView(ISplashView view) {
this.mView = view;
}
protected ISplashView getView() {
return mView;
}
public void didFinishLoading() {
ISplashView view = getView();
if (mConnectionStatus.isOnline()) {
view.showProgress();
view.moveToMainView();
} else {
view.hideProgress();
view.showNoInetErrorMsg();
}
}
}
MVP 的優缺點:
任何事務都存在兩面性,MVP當然也不列外,我們來看看MVP的優缺點。優點:
1. 降低耦合度,實現了Model和View真正的完全分離,可以修改View而不影響Modle
2. 模塊職責劃分明顯,層次清晰(下面會介紹Bob大叔的Clean Architecture)
3. 隱藏數據
4. Presenter可以複用,一個Presenter可以用於多個View,而不需要更改Presenter的邏輯(當然是在View的改動不影響業務邏輯的前提下)
5. 利於測試驅動開發。以前的Android開發是難以進行單元測試的(雖然很多Android開發者都沒有寫過測試用例,但是隨着項目變得越來越複雜,沒有測試是很難保證軟件質量的;而且近幾年來Android上的測試框架已經有了長足的發展——開始寫測試用例吧),在使用MVP的項目中Presenter對View是通過接口進行,在對Presenter進行不依賴UI環境的單元測試的時候。可以通過Mock一個View對象,這個對象只需要實現了View的接口即可。然後依賴注入到Presenter中,單元測試的時候就可以完整的測試Presenter應用邏輯的正確性。
6. View可以進行組件化。在MVP當中,View不依賴Model。這樣就可以讓View從特定的業務場景中脫離出來,可以說View可以做到對業務完全無知。它只需要提供一系列接口提供給上層操作。這樣就可以做到高度可複用的View組件。
7. 代碼靈活性
缺點:
1. Presenter中除了應用邏輯以外,還有大量的View->Model,Model->View的手動同步邏輯,造成Presenter比較笨重,維護起來會比較困難。
2. 由於對視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會過於頻繁。
3. 如果Presenter過多地渲染了視圖,往往會使得它與特定的視圖的聯繫過於緊密。一旦視圖需要變更,那麼Presenter也需要變更了。
4. 額外的代碼複雜度及學習成本。
參考資料:
MVP google官方demo比較分析:http://www.jianshu.com/p/14283d8d3a60
開源項目Philm的MVP架構分析:http://www.devtf.cn/?p=650
Android mvp 架構的自述:http://blog.csdn.net/dantestones/article/details/50899235