MVP 模式接触

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

MVC 和 MVP 的区别

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

  • Model 业务逻辑和实体对象
  • View 布局文件
  • Controller 控制器,也就是常说的 Activity

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


image.png

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

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


image.png

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

  • View 对应着Activity,对应着 View 的绘制和用户之间的 ui 交互
  • Model 和在 MVC 里面的作用一样是业务逻辑和实体对象
  • Presenter 负责完成 View 和 Model 之间的交互。

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


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 来说最重要的就是处理两者之间的关系,作为一个协调者。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容