zoukankan      html  css  js  c++  java
  • MVP架构模式

    • 概念解释
      • MVP是Model(数据) View(界面) Presenter(表现层)的缩写,它是MVC架构的变种,强调Model和View的最大化解耦和单一职责原则
      • Model:负责数据的来源和封装,比如网络请求类,数据库操作类以及java bean,如果有必要则提供接口暴露自己处理数据的状态和进度。
      • View:负责UI相关,如布局UI的初始化,各种listener的设置。在Android中,我们通常写的Activity和Fragment就是属于View层;在web开发中,html则是View层。
      • Controller:业务逻辑控制器,主要负责当获取到数据后对数据进行逻辑处理,然后将数据绑定到View上;比如:请求一个url,从网络获取到数据,进行解析javabean,然后各种set数据。对于控制器的概念大家很好理解,因为我们每天都在这样做,在Activity中请求数据然后更新UI。但是结合View的概念来看,很显然Activity和Fragment不但承担了View的任务,还负责完成的Controller的功能,随着业务功能的增多,Activity的代码越来越难以阅读和维护,这就是在Android中使用MVC的弊端,为了解决MVC模式下View层的臃肿,MVP模式应运而生。
      • Presenter:专门从C独立出来的业务逻辑层,主要负责处理原先View层的业务逻辑,解决了Activity的臃肿问题,让Activity只负责处理UI,职责更加明确;并且将View层的业务逻辑抽取到P层之后,View层与Model层也实现了解耦;便于后期代码的扩展和维护,并且业务逻辑层独立后代码还得到很大的重用性
      • 总结:MVC模式下,V和C纠缠不清,并且View和Model相互关联,而MVP模式下Model和VIew解耦,便于单元测试,项目维护,代码重用
    • 先看看一个登录界面的业务逻辑和UI更新全部写在Activity的代码:

      public class LoginActivity extends ActionBarActivity implements OnClickListener{
          EditText etUsername,etPassword;
          Button btn_login;
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              etUsername = (EditText) findViewById(R.id.et_username);
              etPassword = (EditText) findViewById(R.id.et_password);
              btn_login = (Button) findViewById(R.id.btn_login);
      
              //设置点击事件
              btn_login.setOnClickListener(this);
          }
          @Override
          public void onClick(View v) {
              switch (v.getId()) {
              case R.id.btn_login:
                  String username = etUsername.getText().toString();
                  String password = etPassword.getText().toString();
      
                  if(checkInput(username,password)){
                      //提交登录
                      //执行登录请求
                      execLogin(username, password);
                  }
      
                  break;
              }
          }
          //执行登录请求
          public void execLogin(String username,String password){
              //执行登录请求的伪代码
              HttpHelper helper = new HttpHelper();
              helper.execRequest("http://www.baidu.com", new HttpCallback() {
                  @Override
                  public void onSuccess() {
                      //提示登录成功
                      showLoginSuccess(LoginActivity.this);
      
                      //保存登录相关数据,如登录的标记,用户的唯一标识
                      saveLoginData();
                  }
                  @Override
                  public void onFail() {
                      //关闭登录对话框
                      hideLoginDialog(LoginActivity.this);
                      //提示登录失败
                      showLoginFail(LoginActivity.this);
                  }
              });
          }
          //保存登录数据
          public void saveLoginData(){
              //保存登录相关的数据,代码略过...
          }
          //提示登录成功
          public void showLoginFail(Context context){
              Toast.makeText(context, "登录失败", 0).show();
          }
          //提示登录失败
          public void showLoginSuccess(Context context){
              Toast.makeText(context, "登录成功", 0).show();
          }
          //检查输入的合法性
          private boolean checkInput(String username, String password) {
              boolean result = true;
              //1.检查为空
              if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){
                  Toast.makeText(this, "用户名或者密码不能为空!", 0).show();
                  result = false;
              }
              //2.检查长度
              if(username.length()!=11){
                  Toast.makeText(this, "用户名长度不正确!", 0).show();
                  result = false;
              }
              if(password.length()<5){
                  Toast.makeText(this, "密码长度不能小于5位!", 0).show();
                  result = false;
              }
              return result;
          }
      }

      现在抽取出LoginPresenter类,如下:

      /**
       * 业务逻辑封装层
       * @author lxj
       *
       */
      public class LoginPresenter {
          private ILoginView loginView;
          
          /**
           * 生命周期相关方法
           */
          public void onDestory(){
              //do something to release and avoid memory leak;
          }
          public void onStart(){
              //do something when onStart
          }
          public void onStop(){
              //do something when onStop
          }
          public void onResume(){
              //do something when onResume
          }
          public void onPause(){
              //do something when onPause
          }
          
          public LoginPresenter(ILoginView loginView){
              this.loginView = loginView;
          }
          //登录的方法
          public void login(String username, String password) {
              if(!checkInput(username, password)){
                  return;
              }
              // 执行登录请求的伪代码
              HttpHelper helper = new HttpHelper();
              helper.execRequest("http://www.baidu.com", new HttpCallback() {
                  @Override
                  public void onSuccess() {
                      // 需要UI展示,暴露接口
                      loginView.showLoginSuccess();
                      // 保存登录相关数据,如登录的标记,用户的唯一标识
                      saveLoginData();
                  }
                  @Override
                  public void onFail() {
                      // 需要UI展示,暴露接口
                      loginView.showLoginFail();
                  }
              });
          }
          private void saveLoginData() {
              //do something
          }
          // 检查输入的合法性
          private boolean checkInput(String username, String password) {
                  boolean result = true;
                  // 1.检查为空
                  if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
                      loginView.showInputNoNull();
                      result = false;
                  }
                  // 2.检查长度
                  if (username.length() != 11) {
                      loginView.showUsernameLengthError();
                      result = false;
                  }
                  return result;
              }
      }

      View和P解耦接口如下ILoginView:

      public interface ILoginView {
          void showLoginSuccess();
          void showLoginFail();
          void showInputNoNull();
          void showUsernameLengthError();
      }

      最后的View层编写如下:

      public class LoginActivity extends Activity implements OnClickListener,ILoginView{
          EditText etUsername,etPassword;
          Button btn_login;
          private LoginPresenter loginPresenter;
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              etUsername = (EditText) findViewById(R.id.et_username);
              etPassword = (EditText) findViewById(R.id.et_password);
              btn_login = (Button) findViewById(R.id.btn_login);
              //设置点击事件
              btn_login.setOnClickListener(this);
              //与loginPresenter交互
              loginPresenter = new LoginPresenter(this);
              
          }
          @Override
          public void onClick(View v) {
              switch (v.getId()) {
              case R.id.btn_login:
                  String username = etUsername.getText().toString();
                  String password = etPassword.getText().toString();
                  loginPresenter.login(username,password);
                  break;
              }
          }
          public void showLoginSuccess(){
              Toast.makeText(this, "登录成功", 0).show();
          }
          public void showLoginFail(){
              Toast.makeText(this, "登录失败", 0).show();
          }
          public void showInputNoNull(){
              Toast.makeText(this, "用户名和密码不能为空!", 0).show();
          }
          public void showUsernameLengthError(){
              Toast.makeText(this, "用户名长度不正确!", 0).show();
          }
          public void hideLoginDialog(){
              if(progressDialog!=null){
                  progressDialog.dismiss();
              }
          }
          
          @Override
          protected void onResume() {
              super.onResume();
              loginPresenter.onResume();
          }
          @Override
          protected void onStart() {
              super.onStart();
              loginPresenter.onStart();
          }
          @Override
          protected void onStop() {
              super.onStop();
              loginPresenter.onStop();
          }
          
          @Override
          protected void onPause() {
              super.onPause();
              loginPresenter.onPause();
          }
          
          @Override
          protected void onDestroy() {
              super.onDestroy();
              loginPresenter.onDestory();
          }
      }

      总结:MVP只是给我们提出了分层解耦的思想,并没有一个固定的实现。Google虽然出了官方的MVP实现示例,但是并没有太多人去跟随,很多公司在对Presenter层都有自己的理解,此处的案例相对来说比较规范,对MVP三层都有清晰的解耦和实现,在茫茫开源项目中,算是比较好的容易理解的上手项目了。

  • 相关阅读:
    Spring Security教程(一)
    java报错:The reference to entity "characterEncoding" must end with the ';' delimiter.
    SpringBoot定时任务升级篇(动态添加修改删除定时任务)
    SpringBoot几种定时任务的实现方式
    JDK中的Timer和TimerTask详解
    SpringMVC拦截器与SpringBoot自定义拦截器
    Java注解入门
    Servlet 4.0 入门
    spring邮件发送
    class path resource [spring/ApplicationContext-springmvc.xml] cannot be opened because it does not exist
  • 原文地址:https://www.cnblogs.com/yegong0214/p/6533340.html
Copyright © 2011-2022 走看看