MVP 模式接触

2019-02-13  本文已影响0人  虚心学习的小来子

以前查看别人的时候会看不懂别人的项目结构,里面有个 presenter,其实代码勉强看得懂,但是逻辑会感觉很混乱,所以后来学习了下 MVP 模式,现在需要整理一下。

MVC 和 MVP 的区别

说起 MVP 模式不得不提起 MVC 模式,也是我们接触最多,也应该是最早接触的,虽然一开始的时候感觉自己写的连 MVC 模式都谈不上😁。
MVC 模式的全程是 Model-View-Controller

MVC 模式在小型的项目上面很适用,说白了就是简单粗暴,逻辑简单,View 就是布局,实际的关于数据绑定的工作都是交给 Activity 来完成,这样子搞得 Activity 又像 Controller 又像是 View,借用网上的图来表示这种关系


image.png

也就是说由于 Activity 的职责很模糊,就会导致 Data 和 View 的关系很乱。

而如果换做是 MVP 模式的话,关系则就会清晰很多


image.png

其中 MVP 代表的是 Model-View-Presenter,其中最大的特点就是 Presenter,它是 Model 和 View 之间的桥梁,它们分别的作用如下所示:

和上面的图描述的一样,接下来的一张图则更加明了,是一张很经典的描述两种模式区别的图


image.png

总结

MVP 减少了 Activity 要做的事情,简化了它的代码,把许多事情放到 Presenter 里面去完成,模块划分清楚,层次清楚,从而降低了耦合(这里的低耦合,我通俗的理解就是在 MVP 模式里面,View 和 Presenter 之间,Presenter 和 Model之间可能互相都持有引用(这里错了,是只能 Presenter 持有 Model),但是 View 不会持有 Presenter 的引用,反之也没有)。

例子分析

这里我们拿一个登录的例子来说这个问题,首先我们先看下这个项目架构,是不是感觉分的很清晰,Model 层,Presenter 层和 View 层都分的很清楚。

image.png

Model 层实现

userBean 类

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;
    }

    @Override
    public String toString() {
        return "User(" + "\n" + "userName = " + userName + "\n" + "password = " + password + ")";
    }

}

定义的 LoginModel 接口规定 Model 类要实现的功能,当然是登录,但是这里要注意的是这里面使用的 OnLoginFinishListener 这个接口是 Presenter 里面的,通过它,Presenter 才能知道是否登录成功。

public interface LoginModel {

    void login(UserBean userBean, OnLoginFinishListener onLoginFinishListener);

}

接着是 LoginModelImpl 这个 LoginModel 的实现类

public class LoginModelImpl implements LoginModel {

    @Override
    public void login(UserBean userBean, final OnLoginFinishListener onLoginFinishListener) {

        final String userName = userBean.getUserName();
        final String password = userBean.getPassword();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {

                boolean error = false;

                if (userName == null || userName.isEmpty()) {
                    onLoginFinishListener.onUserError();
                    error = true;
                }

                if (password == null || password.isEmpty()) {
                    onLoginFinishListener.onPasswordError();
                    error = true;
                }

                if (!error) {
                    onLoginFinishListener.onSuccess();
                }

            }
        }, 2000);

    }

}

View 类的实现

LoginView 接口,定义 Acitivity 要完成哪些交互。

public interface LoginView {

    void setUserError();

    void setPasswordError();

    void onSuccess();

}

接着是这个接口的实现类,在这里面实例化一个 Presenter 并持有它,通过 presenter 的实例对象来完成具体的登录和 onDestroy 里面的释放操作,释放掉对 view 的持有,也就是 activity 的持有(这里涉及内存泄漏的知识)。同时也要实现一些 ui 的交互,也就是 LoginView 接口里面定义的方法。

public class LoginActivity extends AppCompatActivity implements View.OnClickListener, LoginView {

    private EditText userEditText;
    private EditText passwordEditText;
    private Button loginButton;
    private LoginPresenter loginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        userEditText = (EditText)findViewById(R.id.et_user_name);
        passwordEditText = (EditText)findViewById(R.id.et_password);
        loginButton = (Button)findViewById(R.id.btn_login);
        loginButton.setOnClickListener(this);
        loginPresenter = new LoginPresenterImpl(this);

    }

    @Override
    protected void onDestroy() {
        loginPresenter.onDestroy();
        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_login:
                UserBean userBean = new UserBean();
                userBean.setUserName(userEditText.getText().toString());
                userBean.setPassword(passwordEditText.getText().toString());
                loginPresenter.validateUser(userBean);
                break;
        }
    }

    @Override
    public void setUserError() {
        Toast.makeText(this, "用户名错误", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void setPasswordError() {
        Toast.makeText(this, "密码错误", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSuccess() {
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
    }

}

最重要的 Presenter 层

LoginPresenter 类,只用实现两个方法,一个是登录,一个是销毁。

public interface LoginPresenter {

    void validateUser(UserBean userBean);

    void onDestroy();

}

之前提到的 OnLoginFinishListener

public interface OnLoginFinishListener {

    void onUserError();

    void onPasswordError();

    void onSuccess();

}

LoginPresenter 的实现类,这里在登录方法里面调用 Model 的登录,并且在登录的回调里面调用 LoginView 的方法,通过这么做来链接 Model 层和 View 层,由此可见对于 MVP 模式而言,最重要的是 Presenter 层,View 层和 Model 层只要管好自己的事,Model 层管好业务逻辑,View 层管好 ui 交互,而对于 presenter 来说最重要的就是处理两者之间的关系,作为一个协调者。

上一篇下一篇

猜你喜欢

热点阅读