介绍

MVC:
  • View:对应于布局文件
  • Model:业务逻辑和实体模型
  • Controllor:对应于Activity
实际上关于该布局文件中的数据绑定的操作,事件处理的代码都在Activity中,造成了Activity既像View又像Controller

程序员对于MVP的普遍的认识是:代码很清晰,不过增加了很多类
当将架构改为MVP以后,Presenter的出现,将Actvity视为View层,Presenter负责完成View层与Model层的交互。现在是这样的:
  • View 对应于Activity,负责View的绘制以及与用户交互
  • Model 依然是业务逻辑和实体模型
  • Presenter 负责完成View和Model间的交互
从并不标准的MVC到MVP的一个转变,减少了Activity的职责,简化了Activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理。
与之对应的好处就是,耦合度更低,更方便的进行测试。

MVC与MVP的一个区别示意图:

其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。
还有一点就是Presenter与View之间的交互是通过接口的。

案例



Activity包(view包)

/**
 * 梳理此Activity所有需要的方法,将这些方法全部封装到一个接口中
 * @author 白乾涛
 */
public interface IUserLoginView {
    public String getUserName();
    public String getPassword();
    public void clearUserName();
    public void clearPassword();
    public void toMainActivity(User user);
    public void showFailedError();
    public void showLoading();
    public void hideLoading();
}

/**
 * 简单来说,对Activity的所有操作(方法)都被剖离在了两个地方,一个是在IUserLoginView中,这里面都是对Activity的一些最基本的操作
 * 另一个在Presenter中,比较复杂的【业务逻辑】都会放在这里(目的当然是减少Activity的代码逻辑)
 * 一定要明白,之所以将Activity中的这些方法剖离在IUserLoginView中,是为了在Presenter中能通过操作IUserLoginView来操作Activity(扩展性)
 * 
 * @author 白乾涛
 */
public class UserLoginActivity extends Activity implements IUserLoginView, OnClickListener {
    private EditText id_et_username;
    private EditText id_et_password;
    private Button id_btn_login;
    private Button id_btn_clear;
    private UserLoginPresenter mUserLoginPrestener = new UserLoginPresenter(this);//这里是将IUserLoginView接口的实例(即Activity)传给了Presenter
    private ProgressBar id_progressbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_login);
        id_et_username = (EditText) findViewById(R.id.id_et_username);
        id_et_password = (EditText) findViewById(R.id.id_et_password);
        id_btn_login = (Button) findViewById(R.id.id_btn_login);
        id_btn_clear = (Button) findViewById(R.id.id_btn_clear);
        id_progressbar = (ProgressBar) findViewById(R.id.id_progressbar);
        id_btn_login.setOnClickListener(this);
        id_btn_clear.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.id_btn_login:
            //这里面的两个方法在Presenter中,当我们需要修改业务逻辑时,只需修改Prestener类中的相应方法即可!
            mUserLoginPrestener.login();
            break;
        case R.id.id_btn_clear:
            mUserLoginPrestener.clear();
            break;
        }
    }
    //******************************************************************************************
    @Override
    public String getUserName() {
        return id_et_username.getText().toString();
    }
    @Override
    public String getPassword() {
        return id_et_password.getText().toString();
    }
    @Override
    public void clearUserName() {
        id_et_username.setText("");
    }
    @Override
    public void clearPassword() {
        id_et_password.setText("");
    }
    @Override
    public void toMainActivity(User user) {
        Toast.makeText(getApplicationContext(), user.getUsername() + "--登录成功", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void showFailedError() {
        Toast.makeText(getApplicationContext(), "登录失败", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void showLoading() {
        id_progressbar.setVisibility(View.VISIBLE);
    }
    @Override
    public void hideLoading() {
        id_progressbar.setVisibility(View.INVISIBLE);
    }
}

presenter包

/**
 * 这就是传说中的Prestener,这里面封装的都是Activity中复杂的业务逻辑
 * @author 白乾涛
 */
public class UserLoginPresenter {
    private IUserBiz userBiz;
    private IUserLoginView userLoginView;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
        };
    };
    //在构造Prestener时,需要传递一个IUserLoginView接口的实例(其实就是Activity),只有这样,Prestener才能对此实例进行操作
    public UserLoginPresenter(IUserLoginView userLoginView) {
        this.userBiz = new UserBiz();
        this.userLoginView = userLoginView;
    }
    public void login() {
        userLoginView.showLoading();
        //为了更具扩展性及进一步解耦,具体的登录逻辑又通过同样的方式转移到了IUserBiz接口上(统一放在biz包下)
        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();
                    }
                });
            }
        });
    }
    public void clear() {
        userLoginView.clearPassword();
        userLoginView.clearUserName();
    }
}

bean包

/**
 * 一个业务bean,所有需要被操作的基本元素(不包括View)都应该定义在这里
 * @author 白乾涛
 */
public class User {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

biz(业务)包

/**
 * 复杂的业务逻辑在这里定义:如,登录、忘记密码、联系客服
 * @author 白乾涛
 */
public interface IUserBiz {
    public void login(String username, String password, OnLoginListener onLoginListener);
}

/**
 * 复杂业务逻辑的具体实现:如具体的登录代码在这里编写
 * 这里面有一个回调
 * @author 白乾涛
 */
public class UserBiz implements IUserBiz {
    @Override
    public void login(final String username, final String password, final OnLoginListener onLoginListener) {
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if ("username".equals(username) && "password".equals(password)) {
                    User user = new User();
                    user.setUsername(username);
                    user.setPassword(password);
                    //成功时的回调
                    onLoginListener.loginSuccess(user);
                } else {
                    //失败时的回调
                    onLoginListener.loginFailed();
                }
            }
        }.start();
    }
}

/**
 * 这个其实不算是MVP中的东西(但一般都会有),这是一个回调,当执行复杂逻辑的同时做一些回调处理
 * @author 白乾涛
 */
public interface OnLoginListener {
    public void loginSuccess(User user);
    public void loginFailed();
}

MVP模式 详解 案例的更多相关文章

  1. Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...

  2. Extjs MVC开发模式详解

    Extjs MVC开发模式详解   在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开发模式, ...

  3. JavaScript严格模式详解

    转载自阮一峰的博客 Javascript 严格模式详解   作者: 阮一峰 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict m ...

  4. HTTP协议头部与Keep-Alive模式详解

    HTTP协议头部与Keep-Alive模式详解 .什么是Keep-Alive模式? 我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器 ...

  5. (" use strict")Javascript 严格模式详解

    Javascript 严格模式详解 转载别人的博客内容,浏览了一遍,没有全部吸收,先保存一下链接 http://www.ruanyifeng.com/blog/2013/01/javascript_s ...

  6. HTTP协议Keep-Alive模式详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp22 HTTP协议Keep-Alive模式详解 1.什么是Keep-Aliv ...

  7. Java开源生鲜电商平台-盈利模式详解(源码可下载)

    Java开源生鲜电商平台-盈利模式详解(源码可下载) 该平台提供一个联合买家与卖家的一个平台.(类似淘宝购物,这里指的是食材的购买.) 平台有以下的盈利模式:(类似的平台有美菜网,食材网等) 1. 订 ...

  8. ext.js的mvc开发模式详解

    ext.js的mvc开发模式详解和环境配置 在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开 ...

  9. Docker Kubernetes Service 网络服务代理模式详解

    Docker Kubernetes  Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...

随机推荐

  1. 【USACO 1.3.4】牛式

    [題目描述 ] 下面是一个乘法竖式,如果用我们给定的那n个数字来取代*,可以使式子成立的话,我们就叫这个式子牛式. * * * x * * ---------- * * * * * * ------- ...

  2. 用jquery修改默认的单选框radio或者复选框checkbox选择框样式

    默认的radio和checkbox选框很难看.我去看了一下qq注册的页面.发现单选和复选框并没有用<input>,居然是用是A标签.然后用css背景图片展示选择框,用JavaScript控 ...

  3. 文件上传-html

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>文件 ...

  4. 正则表达式 U贪婪模式

    <?php/*模式修正符号: i u 位置:"//模式修正符位置" 可以一次使用一个,也可以一次使用多个 对整个正则表达式调优用的,也可以说是对正则表达式功能的扩展 &quo ...

  5. jquery 的日期时间控件(年月日时分秒)

    <!-- import package --> <script type="text/javascript" src="JS/jquery.js&quo ...

  6. .ctor,.cctor 以及 对象的构造过程

    摘要: .ctor,.cctor 以及 对象的构造过程.ctor:简述:构造函数,在类被实例化时,它会被自动调用.当C#的类被编译后,在IL代码中会出现一个名为.ctor的方法,它就是我们的构造函数, ...

  7. 深入理解javascript闭包(一)

    原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...

  8. php设计模式之简单工厂模式

    ①抽象基类:类中定义抽象一些方法,用以在子类中实现 ②继承自抽象基类的子类:实现基类中的抽象方法 ③工厂类:用以实例化所有相对应的子类 /** * * 定义个抽象的类,让子类去继承实现它 * */ a ...

  9. 关于自定义Adapter实现ListView的使用

    以下为使用BaseAdapter作扩展,自定义Adapter来使用ListView控件: 需要注意以下的几点: 1.自定义Adapter时,需要特别注意Adapter类中getView()方法覆盖,注 ...

  10. 用java模拟银行柜台排队

    4年前在办理银行业务的时候,看到每个办理柜台窗口前都有很多人排队. 同时在那个时间段,我正好重温了数据结构这本书.好像里面有提到银行. 所以当时就用java写了一段小程序来模拟窗口排队的情况. 有兴趣 ...