一.概述
MVP(Model-View-Presenter) 是總所周知MVC模式的一個演變,他們的主要目的都是劃分模塊職責,降低模塊耦合,易測試,提高代碼複用,這裏主要針對Android平臺來簡單分析MVP.
1.層級責任
Model: 負責數據的檢索,持久化等操作
View: 負責UI的繪製和用戶的交互
Presenter: 作爲Model和View的中間協調部分,負責兩者之間的業務邏輯處理
2.與MVC模式的區別
MVP模式與MVC模式從層級數據流向上來說一個主要的區別應該就是:MVC模式允許View層和Model層直接通訊.從圖1和圖2可以看到MVP和MVC的區別.
圖1MVC模式中Model可以直接update data 到View層。所以當某個View的功能很複雜的時候,View和Model的耦合度可能會很高(並且在android的開發中Activity通常會充當controller&view的角色,結果Activity就很臃腫).而MVP模式就沒有這個問題,View會抽象出來一系列操作UI的接口(Model層也可以),Presenter拿到的都是其他兩個層級的接口來做業務邏輯的處理.這樣不僅可以使View和Model之間的耦合度降低,還可以更易得進行單元測試.
圖1:MVC模式
圖2:MVP模式
3.MVP的優缺點
優點:降低耦合,層級職責更明顯,易於單元測試
缺點:造成類數量爆炸,代碼複雜度和學習成本高,在某些場景下presenter的複用會產生接口冗餘
二. MVP簡單的實例
1.項目結構
2.Model層
包含有一個實體UserBean用來承載數據和UserBiz來對登陸數據判斷
- public class UserBean {
- private String username;
- private String password;
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- }
UserBiz通過抽象出一個接口
- public interface UserBiz {
- public void login(UserBean login);
- }
UserBizImpl實例化接口,並且通過登陸監聽將結果回調給Presenter
- public class UsrBizImpl implements UserBiz{
- private OnLoginListener listener;
- public UsrBizImpl(OnLoginListener listener){
- this.listener = listener;
- }
- @Override
- public void login(UserBean login) {
- boolean status = false;
- String username,password;
- username = login.getUsername();
- password = login.getPassword();
- if (username != null && "asdf".equals(username))
- if (password != null && "123".equals(password))
- status = true;
- listener.loginStatus(status);
- }
- }
3.View層
把View層針對控件操作抽象出來一些列的接口
- public interface LoginView {
- public String getUsername();
- public String getPassword();
- public void clearUsername();
- public void clearPassword();
- public void showMsg(String msg);
- }
在Activity裏面實現該接口的控件操作,並且初始化Presenter,這是可以看到Activity裏面沒有邏輯處理,只是對UI的控件進行數據或者行爲的操作,所有的動作都是有Presenter的接口來實現,這樣在項目裏面會極大得精簡Activity的體積.
- public class LoginActivity extends Activity implements LoginView{
- private EditText username, password;
- private Button login, clear;
- private LoginPresenter loginPresenter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_login);
- init();
- }
- private void init(){
- loginPresenter = new LoginPresenterImpl(this);
- username = (EditText) findViewById(R.id.username);
- password = (EditText) findViewById(R.id.pass);
- login = (Button) findViewById(R.id.login);
- clear = (Button) findViewById(R.id.clear);
- login.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- loginPresenter.login();
- }
- });
- clear.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- loginPresenter.clear();
- }
- });
- }
- @Override
- public String getUsername() {
- return username.getText().toString();
- }
- @Override
- public String getPassword() {
- return password.getText().toString();
- }
- @Override
- public void clearUsername() {
- username.setText("");
- }
- @Override
- public void clearPassword() {
- password.setText("");
- }
- @Override
- public void showMsg(String msg) {
- Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
- }
- }
4.Presenter層
在Presenter層裏面,Presenter掌握着View和Model的所有接口,Presenter就可以根據不同的業務邏輯通過MV兩層的接口來實現特定的功能,讓M和V獨立出來.
- public class LoginPresenterImpl implements LoginPresenter, OnLoginListener{
- private UserBiz userBiz;
- private LoginView loginView;
- public LoginPresenterImpl(LoginView loginView){
- this.loginView = loginView;
- userBiz = new UsrBizImpl(this);
- }
- @Override
- public void login() {
- UserBean login = new UserBean();
- login.setUsername(loginView.getUsername());
- login.setPassword(loginView.getPassword());
- userBiz.login(login);
- }
- @Override
- public void clear() {
- loginView.clearPassword();
- loginView.clearUsername();
- }
- @Override
- public void loginStatus(boolean status) {
- String msg;
- if (status)
- msg = "login succeed";
- else
- msg = "login failed";
- loginView.showMsg(msg);
- }
- }
5.Demo下載地址
三.總結
簡單得用了下MVP,也有跟朋友討論了一下,好多人都說這個看着挺不錯的,但是用着很麻煩。確實現在Android項目用MVP的不是佔多數,帶着一些疑惑樓主就想去了解一下android原生程序裏面是用的什麼風格的,之前也有看過一些android源碼,但是都是斷斷續續的,也好久沒有寫過博客了,本着對技術的熱愛,計劃重新開啓擼android源碼的計劃(從Android原生的系統程序到framework再一路向下),現在希望自己能夠堅持下來,並且產出一個博客的系列和大家一起分享和成長.