MVP模式 詳解 案例



介紹
      
      
      
              
MVC:
  • View:對應於布局文件
  • Model:業務邏輯和實體模型
  • Controllor:對應於Activity
實際上關於該布局文件中的數據綁定的操作,事件處理的代碼都在Activity中,造成了Activity既像View又像Controller

程序員對於MVP的普遍的認識是: 代碼很清晰,不過增加了很多類
當將架構改為MVP以后,Presenter的出現,將Actvity視為View層,Presenter負責完成View層與Model層的交互。現在是這樣的:
  • View 對應於Activity,負責View的繪制以及與用戶交互
  • Model 依然是業務邏輯和實體模型
  • Presenter 負責完成View和Model間的交互
從並不標准的MVC到MVP的一個轉變,減少了Activity的職責,簡化了Activity中的代碼,將復雜的邏輯代碼提取到了Presenter中進行處理
與之對應的好處就是,耦合度更低,更方便的進行測試。

MVC與MVP的一個區別示意圖:

其實最明顯的區別就是,MVC中是允許Model和View進行交互的,而MVP中很明顯,Model與View之間的交互由Presenter完成
還有一點就是Presenter與View之間的交互是通過接口的。

案例
       
       
       
               


Activity包(view包)
      
      
      
              
/**
 * 梳理此Activity所有需要的方法,將這些方法全部封裝到一個接口中
 * @author 白乾濤
 */
public interface IUserLoginView {
    public String getUserName();
    public String getPassword();
    public void clearUserName();
    public void clearPassword();
    public void toMainActivity(User user);
    public void showFailedError();
    public void showLoading();
    public void hideLoading();
}

/**
 * 簡單來說,對Activity的所有操作(方法)都被剖離在了兩個地方,一個是在IUserLoginView中,這里面都是對Activity的一些最基本的操作
 * 另一個在Presenter中,比較復雜的【業務邏輯】都會放在這里(目的當然是減少Activity的代碼邏輯)
 * 一定要明白,之所以將Activity中的這些方法剖離在IUserLoginView中,是為了在Presenter中能通過操作IUserLoginView來操作Activity(擴展性)
 * 
 * @author 白乾濤
 */
public class UserLoginActivity extends Activity implements IUserLoginView, OnClickListener {
    private EditText id_et_username;
    private EditText id_et_password;
    private Button id_btn_login;
    private Button id_btn_clear;
    private UserLoginPresenter mUserLoginPrestener = new UserLoginPresenter(this);//這里是將IUserLoginView接口的實例(即Activity)傳給了Presenter
    private ProgressBar id_progressbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_login);
        id_et_username = (EditText) findViewById(R.id.id_et_username);
        id_et_password = (EditText) findViewById(R.id.id_et_password);
        id_btn_login = (Button) findViewById(R.id.id_btn_login);
        id_btn_clear = (Button) findViewById(R.id.id_btn_clear);
        id_progressbar = (ProgressBar) findViewById(R.id.id_progressbar);
        id_btn_login.setOnClickListener(this);
        id_btn_clear.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.id_btn_login:
            //這里面的兩個方法在Presenter中,當我們需要修改業務邏輯時,只需修改Prestener類中的相應方法即可!
            mUserLoginPrestener.login();
            break;
        case R.id.id_btn_clear:
            mUserLoginPrestener.clear();
            break;
        }
    }
    //******************************************************************************************
    @Override
    public String getUserName() {
        return id_et_username.getText().toString();
    }
    @Override
    public String getPassword() {
        return id_et_password.getText().toString();
    }
    @Override
    public void clearUserName() {
        id_et_username.setText("");
    }
    @Override
    public void clearPassword() {
        id_et_password.setText("");
    }
    @Override
    public void toMainActivity(User user) {
        Toast.makeText(getApplicationContext(), user.getUsername() + "--登錄成功", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void showFailedError() {
        Toast.makeText(getApplicationContext()"登錄失敗", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void showLoading() {
        id_progressbar.setVisibility(View.VISIBLE);
    }
    @Override
    public void hideLoading() {
        id_progressbar.setVisibility(View.INVISIBLE);
    }
}

presenter包
      
      
      
              
/**
 * 這就是傳說中的Prestener,這里面封裝的都是Activity中復雜的業務邏輯
 * @author 白乾濤
 */
public class UserLoginPresenter {
    private IUserBiz userBiz;
    private IUserLoginView userLoginView;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
        };
    };
    //在構造Prestener時,需要傳遞一個IUserLoginView接口的實例(其實就是Activity),只有這樣,Prestener才能對此實例進行操作
    public UserLoginPresenter(IUserLoginView userLoginView) {
        this.userBiz = new UserBiz();
        this.userLoginView = userLoginView;
    }
    public void login() {
        userLoginView.showLoading();
        //為了更具擴展性及進一步解耦,具體的登錄邏輯又通過同樣的方式轉移到了IUserBiz接口上(統一放在biz包下)
        userBiz.login(userLoginView.getUserName()userLoginView.getPassword()new OnLoginListener() {
            @Override
            public void loginSuccess(final User user) {
                //需要再UI線程執行
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.toMainActivity(user);
                        userLoginView.hideLoading();
                    }
                });
            }
            @Override
            public void loginFailed() {
                //需要在UI線程執行
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.showFailedError();
                        userLoginView.hideLoading();
                    }
                });
            }
        });
    }
    public void clear() {
        userLoginView.clearPassword();
        userLoginView.clearUserName();
    }
}

bean包
       
       
       
               
/**
 * 一個業務bean,所有需要被操作的基本元素(不包括View)都應該定義在這里
 * @author 白乾濤
 */
public class User {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

biz(業務)包
       
       
       
               
/**
 * 復雜的業務邏輯在這里定義:如,登錄、忘記密碼、聯系客服
 * @author 白乾濤
 */
public interface IUserBiz {
    public void login(String username, String password, OnLoginListener onLoginListener);
}

/**
 * 復雜業務邏輯的具體實現:如具體的登錄代碼在這里編寫
 * 這里面有一個回調
 * @author 白乾濤
 */
public class UserBiz implements IUserBiz {
    @Override
    public void login(final String username, final String password, final OnLoginListener onLoginListener) {
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if ("username".equals(username) && "password".equals(password)) {
                    User user = new User();
                    user.setUsername(username);
                    user.setPassword(password);
                    //成功時的回調
                    onLoginListener.loginSuccess(user);
                } else {
                    //失敗時的回調
                    onLoginListener.loginFailed();
                }
            }
        }.start();
    }
}

/**
 * 這個其實不算是MVP中的東西(但一般都會有),這是一個回調,當執行復雜邏輯的同時做一些回調處理
 * @author 白乾濤
 */
public interface OnLoginListener {
    public void loginSuccess(User user);
    public void loginFailed();
}






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM