MVP模式入门案例

随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。


四个要素:

(1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);

(2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;

(3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);

(4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。


为什么使用MVP模式

在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter处理).

另外,回想一下你在开发Android应用时是如何对代码逻辑进行单元测试的?是否每次都要将应用部署到Android模拟器或真机上,然后通过模拟用户操作进行测试?然而由于Android平台的特性,每次部署都耗费了大量的时间,这直接导致开发效率的降低。而在MVP模式中,处理复杂逻辑的Presenter是通过interface与View(Activity)进行交互的,这说明了什么?说明我们可以通过自定义类实现这个interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。



MVP与MVC的异同

MVC模式与MVP模式都作为用来分离UI层与业务层的一种开发模式被应用了很多年。在我们选择一种开发模式时,首先需要了解一下这种模式的利弊:

无论MVC或是MVP模式都不可避免地存在一个弊端:额外的代码复杂度及学习成本。
这就导致了这两种开发模式也许并不是很小型应用。

但比起他们的优点,这点弊端基本可以忽略了:

(1)降低耦合度

(2)模块职责划分明显

(3)利于测试驱动开发

(4)代码复用

(5)隐藏数据

(6)代码灵活性


登录Demo案例演示

步骤

  1. 首先完成User Been文件的创建,在这里面,我们只需要要User的serget方法。
  2. 接着思考User有什么业务,并将这些业务统统添加进入IUserBiz接口中。
  3. 每一个业务逻辑都有一个附带的Listener,这个Listener中有执行这个业务后会发生的事情。
  4. 然后UserBiz 将 IUserBiz中的功能实现。
  5. 对应的View(Activity)中的功能写一个 接口出来。
  6. 对应的View(Activity)实现接口。
  7. 实现Presenter,Presenter的作用就是将View与Model进行连接。

步骤一 User Been的创建

仔细看我上面那个登录界面,然后回答:

  • 根据上面的图片如果是你创建一个User,里面有什么属性?

然后你想象我们有登录与清除的功能,那你的User中需要有什么方法?

?	public class User {
    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;
    }

步骤二 IUserBiz接口的创建

思考:我们已经有一个User Been了,我们需要用这个User进行什么操作?并将User即将进行的操作写为抽象方法。

public interface IUserBiz {
    public void login(String username, String password, OnLoginListener loginListener);
}

步骤三 附带的Listener创建

思考:我们之前创建的IUserBiz接口中的方法有哪种情况会发生?并将可能会出现的情况进行写入抽象Listener中去。

public interface OnLoginListener {
    void loginSuccess(User user);
    void loginFailed();
}

步骤四 创建UserBiz直接实现IUserBiz

就是将方法实现

public class UserBiz implements IUserBiz {
    @Override
    public void login(final String username, final String password, final OnLoginListener loginListener) {
        //模拟子线程耗时操作
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //模拟登录成功
                if ("123".equals(username) && "123".equals(password)) {
                    User user = new User();
                    user.setUsername(username);
                    user.setPassword(password);
                    loginListener.loginSuccess(user);
                } else {
                    loginListener.loginFailed();
                }
            }
        }.start();
    }
}

步骤六 将View(Activity)连接创建好的接口并实现

根据接口并实现

public class UserLoginActivity extends ActionBarActivity implements IUserLoginView {
    private EditText mEtUsername, mEtPassword;
    private Button mBtnLogin, mBtnClear;
    private ProgressBar mPbLoading;

    private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_login);

        initViews();
    }

    private void initViews() {
        mEtUsername = (EditText) findViewById(R.id.id_et_username);
        mEtPassword = (EditText) findViewById(R.id.id_et_password);

        mBtnClear = (Button) findViewById(R.id.id_btn_clear);
        mBtnLogin = (Button) findViewById(R.id.id_btn_login);

        mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);

        mBtnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mUserLoginPresenter.login();
            }
        });

        mBtnClear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mUserLoginPresenter.clear();
            }
        });
    }

    @Override
    public String getUserName() {
        return mEtUsername.getText().toString();
    }

    @Override
    public String getPassword() {
        return mEtPassword.getText().toString();
    }

    @Override
    public void clearUserName() {
        mEtUsername.setText("");
    }

    @Override
    public void clearPassword() {
        mEtPassword.setText("");
    }

    @Override
    public void showLoading() {
        mPbLoading.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        mPbLoading.setVisibility(View.GONE);
    }

    @Override
    public void toMainActivity(User user) {
        Toast.makeText(this, user.getUsername() +
                " login success , to MainActivity", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError() {
        Toast.makeText(this,
                "login failed", Toast.LENGTH_SHORT).show();

步骤七 实现Presenter

在MVP中Presenter将Model与View进行一个连接,在这个地方的Presenter属于一个中间人的传话的效果。
那么在这个Presenter类中,主要就是图中Button的方法,也就是一个login方法,一个clear方法,具体实现还是将之前所实现的接口进行一个方法对接。

//将**View**与**Model**之间进行操作。
public class UserLoginPresenter {
    private IUserBiz       userBiz;
    private IUserLoginView userLoginView;
    private Handler mHandler = new Handler();
    ////传递一个loginView
    public UserLoginPresenter(IUserLoginView userLoginView) {

        //这个是View的代表
        this.userLoginView = userLoginView;
        //这个是Model的代表
        this.userBiz = new UserBiz();
    }
    //下面有两个方法主要是将两个**Button**的操作直接封装完成,然后直接使用
    public void login() {
        userLoginView.showLoading();
        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();
                    }
                });

            }
        });
    }
    // //这个是clear按钮
    public void clear() {
        userLoginView.clearUserName();
        userLoginView.clearPassword();
    }

}


解答

一 User Been的创建

仔细看我上面那个登录界面,然后回答:

  • 根据上面的图片如果是你创建一个User,里面有什么属性?
  • 然后你想象我们有登录与清除的功能,那你的User中需要有什么方法?
回答:
1.User有userName与password两个属性。
2.userName与password拥有setget方法即可。

二 IUserBiz接口的创建

思考:我们已经有一个User Been了,我们需要用这个User进行什么操作?
并将User即将进行的操作写为抽象方法。

回答:
User需要有一个login的功能,这个功能中我们需要将我们的账号密码传递进
去,同时还有一个Listener需要监听login的情况,在下面就是Listener的创
建了。

三 附带的Listener创建

思考:我们之前创建的IUserBiz接口中的方法有哪种情况会发生?
并将可能会出现的情况进行写入抽象Listener中去。

回答:
以前接口中主要实现了一个login的功能,这个功能会有两种可能发生,第一
种就是登录成功,第二种就是登录失败。

四 创建UserBiz直接实现IUserBiz

就是将方法实现。

五 将View(Activity)中的功能写入接口

仔细看我上面那个登录界面,然后回答:

  • Activity中有两个Button,点击一下会进行什么操作?
  • 操作过程中会发生什么情况,并将情况转换成对应的方法。
    回答:
    1.点击login会有登录成功或者登录失败,在这里登录需要获取Edit的信息。
    2.点击clear会清除EditView。
    那么方法如下:
    登录成功方法
    登录失败方法
    获取UserName
    获取PassWord
    清除Edit框

六 将View(Activity)连接创建好的接口并实现

根据接口并实现。

七 实现Presenter

在MVP中Presenter将Model与View进行一个连接,在这个地方的Presenter属于一个中间人的传话的效果。
那么在这个Presenter类中,主要就是图中Button的方法,也就是一个login方法,一个clear方法,具体实现还是将之前所实现的接口进行一个方法对接。

时间: 2024-10-21 13:31:53

MVP模式入门案例的相关文章

MVP模式入门(结合Rxjava,Retrofit)

本文MVP的sample实现效果: github地址:https://github.com/xurui1995/MvpSample 老规矩,在说对MVP模式的理解之前还是要再谈谈MVC模式,了解了MVC的缺点.我们才知道为什么要用MVP. 关于MVC的图解,我在网上找到了一些图.如下:    MVC模式在开发web或者管理系统中应用很多,我们的View与人交互,人点击鼠标或者输入一些东西时,View会发送相应的指令给Controller,Controller 接到指令,再去调用Model的方法去

Android开发学习--MVP模式入门

1.模型与视图完全分离,我们可以修改视图而不影响模型2.可以更高效地使用模型,因为所有的交互都发生在一个地方--Presenter内部3.我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑.这个特性非常的有用,因为视图的变化总是比模型的变化频繁.4.如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试) 下面示例一个小案例: 项目架构: 首先bean层: User.java public class User { privat

Mybatis入门案例中设计模式的简单分析

Talk is cheap, show me the code! public class TestMybatis { public static void main(String[] args) throws IOException { //1. 读取配置文件 InputStream resource = Resources.getResourceAsStream("mybatis.xml"); //2. 创建sqlSessionFactory工厂 SqlSessionFactory

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

一  MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and

_00019 Storm的体系结构介绍以及Storm入门案例(官网上的简单Java案例)

博文作者:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前,妳却感觉不到我的存在 技术方向:Flume+Kafka+Storm+Redis/Hbase+Hadoop+Hive+Mahout+Spark ... 云计算技术 转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作! qq交流群:214293307  (期待与你一起学习,共同进步) # Storm

_00017 Flume的体系结构介绍以及Flume入门案例(往HDFS上传数据)

博文作者:妳那伊抹微笑 个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前,妳却感觉不到我的存在 技术方向:hadoop,数据分析与挖掘 转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作! qq交流群:214293307  (期待与你一起学习,共同进步) # 学习前言 想学习一下Flume,网上找了好多文章基本上都说的很简单,只有一半什么的,简直就是坑爹,饿顿时怒火就上来了,学个东西真不容易,然后自己耐心的把这些零零碎碎的东西整理整理,各种

nodejs的入门案例

1.命令行工具 node -v          版本 node -e         eval script(执行eval方法)  例如:node -e "console.log('测试')"; node             直接进入编译模式 nodejs的入门案例

Freemarker入门案例(一)

FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写.FreeMarker被设计用来生成HTMLWeb页面,特别是基于MVC模式的应用程序. 所谓模板,就是一份已经写好了基本内容,有着固定格式的文档,其中空出或者用占位符标识的内容,由使用者来填充,不同的使用者给出的数据是不同的.在模板中的占位符,在模板运行时,由模板引擎来解析模板,并采用动态数据替换占位符部分的内容. FreeMarker不是一个Web应用框架,而适合作为Web应用框架一个组件,FreeMa

ActiveMQ入门案例以及整合Spring的简单实用

先来个ActiveMQ介绍哈: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法,是一个消息中间件. 应用场景:为了实现系统之间的通信,把系统之间的调用耦合度降低就可以使用MQ. 1) activeMQ 是Apache出品,最流行的,能力强劲的开源消息总线. 2) avtiveMQ主要特点:完全支持JMS1.1和J2EE 1.4规范:支持spring,很容易内嵌到spring中:支持ajax. 3) activeMQ的消息形式: a) 点对点形式,即生产