浅析MVP模式

来源:互联网 发布:java参数引用传递 编辑:程序博客网 时间:2024/04/29 18:47

  MVP模式已经流行很长一段时间了,以前只是听到关于MVP的一些东西,譬如:MVP是MVC的进化版,MVP模式让View层和Model层完全解耦了。
  这里先简单回顾一下Android中MVC模式:M即是代表业务逻辑和实体模型;V即是代码对应的View,也就是界面;C即是代表控制层,对应着Activity或者Fragment;但是很多时候数据处理都在Activity或者Fragment中,View可以直接访问Model,这样就不可避免一些业务逻辑了,而且有许多业务逻辑都是在View层处理的,所以导致很多代码也就无法重用了。
  MVP模式与MVC模式最大的区别就是View不与Model打交道,而是通过Presenter来与Model交互,而且Presenter实现的逻辑代码与具体View是没有关联的,它不属于任何具体的View,而只是通过约定好的接口来交互。
  根据一个简单的例子来对MVP模式进行更深刻的理解,图1就是要实现的UI效果,一个简单的登陆界面:
这里写图片描述

图2是项目文件结构图:

这里写图片描述

图3是MVP示意图和项目中各类的对应关系,以便更好地理解:

这里写图片描述

解析:

  • UserBean是实体类,这个没什么可以讲的,直接上代码:
public class UserBean {    private String name;    private String password;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}
  • Model部分是负责数据逻辑处理的部分,这个例子比较简单,就只有登陆这个功能而已,方便我们以后做业务拓展,我们先写一个UserModel 的接口UserModelInterface,代码如下:
public interface UserModelInterface {     void login(String name,String password,LoginListener loginListener);}

UserModel 实现代码如下:

public class UserModel implements UserModelInterface {    @Override    public void login(String name, String password, LoginListener loginListener) {        //判断用户名是否为空        if (TextUtils.isEmpty(name)){            loginListener.nameIsEmpty();            return;        }        //判断密码是否为空        if (TextUtils.isEmpty(password)){            loginListener.passwordIsEmpty();            return;        }        //用户名和密码都不为空的情况下执行登陆操作,这里就实现登陆的网络请求代码了,直接默认登陆成功,如果登陆失败则回调loginListener.loginFailed();        loginListener.loginSuccess();    }}

LoginListener 这个接口主要是用于Model和Presenter的交互,把Model的业务逻辑处理接口返回出去给Presenter,然后Presenter再通过接口(LoginView)把结果返回给View层,这大概就是MVP的模式的核心了,先不急,先上LoginListener的代码:

public interface LoginListener {    void loginSuccess();    void loginFailed();    void nameIsEmpty();    void passwordIsEmpty();}

结合这个案例来讲,无非就两种结果,登陆成功或者失败,然后执行登陆之前要判断用户名和密码是否为空,所以就有以上四个方法了。

  • 接下来看我们用于View(MVPLoginActivity)和Presenter(LoginPresenter)交互的接口–LoginView,这个接口主要是从分析界面来得到的业务逻辑,譬如:用户有在登陆成功后我们需要进行页面的跳转,登陆失败后的我们需要弹出一个Toast来提示用户,或者更改界面提示等等。所以就有以下的代码实现:
public interface LoginView {    String getName();    String getPassword();    void setName(String name);    void setPassword(String password);    void loginSuccess();//登录成功    void loginFailed();//登录失败    void nameIsEmpty();//名字为空    void passwordIsEmpty();//密码为空}
  • 既然说LoginView是用于View和Presenter的交互的,现在问题来了,LoginView是怎么来连接MVPLoginActivity和LoginPresenter的呢?其实很简单,只需要MVPLoginActivity去实现LoginView这个接口,直接上MVPLoginActivity代码:
public class MVPLoginActivity extends AppCompatActivity implements LoginView{    private AutoCompleteTextView email;    private EditText passwordEt;    private Button email_sign_in_button;    private LoginPresenter loginPresenter=new LoginPresenter(this);//实例化Presenter    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);        email= (AutoCompleteTextView) findViewById(R.id.email);        passwordEt= (EditText) findViewById(R.id.password);        email_sign_in_button= (Button) findViewById(R.id.email_sign_in_button);        email_sign_in_button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                loginPresenter.login();//登录登录登录登录登录            }        });    }    @Override    public String getName() {        return email.getText().toString();    }    @Override    public String getPassword() {        return passwordEt.getText().toString();    }    @Override    public void setName(String name) {        email.setText(name);    }    @Override    public void setPassword(String password) {        passwordEt.setText(password);    }    @Override    public void loginSuccess() {        Log.i("ysc","loginSuccess");    }    @Override    public void loginFailed() {        Log.i("ysc","loginFailed");    }    @Override    public void nameIsEmpty() {        Log.i("ysc","nameIsEmpty");    }    @Override    public void passwordIsEmpty() {        Log.i("ysc","passwordIsEmpty");    }}

在这个地方就出现了我们全面说了很多的用于View和Model交互的P(LoginPresenter)这个类了,在界面(MVPLoginActivity )实例化时也实例化LoginPresenter,在点击按钮时执行loginPresenter.login(),然后View就可以不用关系其他情况了,然后在下面看LoginPresenter的代码:

public class LoginPresenter {    private LoginView loginView;    private UserModel userModel;    public LoginPresenter(LoginView loginView) {        this.loginView = loginView;        this.userModel=new UserModel();    }    public void login(){    userModel.login(loginView.getName(), loginView.getPassword(),    new LoginListener() {            @Override            public void loginSuccess() {                loginView.loginSuccess();            }            @Override            public void loginFailed() {                loginView.loginFailed();            }            @Override            public void nameIsEmpty() {                loginView.nameIsEmpty();            }            @Override            public void passwordIsEmpty() {                loginView.passwordIsEmpty();            }        });    }}

先看构造方法

public LoginPresenter(LoginView loginView) {        this.loginView = loginView;        this.userModel=new UserModel();    }

先把Loginview传进来用户与view层的交互,再实例化Model(UserModel),前面有说过业务处理都在Model里,也就是userModel.login()这个方法,然后Model的处理结构通过接口LoginListener来告知LoginPreseter,LoginPresenter再通过Loginview来更新界面,这样就完成View与Model的完全解耦了。

  • LoginView:就是写一些界面需要业务逻辑,然后可以实现相对应的UI操作。
  • MVPLoginActivity:单纯的界面,实现LoginView接口,并且实例化Presenter。
  • Presenter:LoginPreseter作为MVPLoginActivity和UserModel的中间层,把通过LoginView拿到的界面数据传给UserModel处理,UserModel处理完的结果返回回来之后,通过LoginView来更新界面或者做相应的UI操作。
  • MVPLoginActivity和LoginPreseter,LoginPreseter和UserModel之间的交流都是通过接口来处理,前者通过LoginView,后者通过LoginListener。
  • 从以上分析看来MVP模式确实完成了View层和Model的完全解耦

以上就是个人看过很多篇关于MVP方面的博客资料的后,动手写的demo,顺便也写成博客,欢迎多多指正。

0 0
原创粉丝点击