MVP模式分析

来源:互联网 发布:英语作文人工智能 编辑:程序博客网 时间:2024/05/19 03:43

MVP模式分析


一、为什么使用MVP模式

     这个问题我们就得首先从MVC说起了,我们知道MVC曾是我们熟悉的设计框架模式,但是正是MVC设计中存在弊端,所以才使我们程序员追求更好的设计框架。在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。我们可以回想在之前做过的项目中,比如智慧背景,谷歌电子市场中,我们当把整个项目做完之后,对数据Model和视图View可能比较清晰,但是对于Controller就非常模糊了,因为在逻辑业务的处理与视图的操作经常会混合在一起,经常在一个Activity中一起混合处理这两者,所以我们对MVC设计模式中Controller非常的不清晰。简单的来说,MVC设计模式中,我们对控制逻辑业务的部分抽取的不彻底,这个时候我们就需要对Controller进行彻底的抽取,使得这三者之间的逻辑更独立,任务分工更加明确。

    所以,我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中View,它负责UI元素的初始化,通过接口建立UI元素与Presenter的关联,复杂的逻辑交由Presenter处理,这就产生了MVP模式。

总结:MVC模式对逻辑业务的抽取不彻底,MVP是对数据、视图、逻辑三大模块更加彻底分工的设计模式


二、什么是MVP模式?

MVP代表Model,View和Presenter。

View层负责处理用户事件和视图部分的展示。在Android中,它可能是Activity或者Fragment类。负责UI的绘制和用户的交互

Model层负责访问数据。数据可以是远端的Server API,本地数据库或者SharedPreference等。 负责数据的检索,持久化等操作

Presenter层是连接(或适配)View和Model的桥梁。作为Model和View的中间协调部分,负责两者之间的业务逻辑处理


三、MVP模式的优缺点

优点:

1降低了数据与视图之间的耦合,

2层级职责更明显,

3易于单元测试

缺点:

1造成类数量增加,代码复杂度增加

2在某些场景下presenter的复用会产生接口冗余

3presenter中持有视图的引用,容易造成内存泄漏


四、MVP与MVC模式的区别

MVP模式与MVC模式从层级数据流向上来说一个主要的区别应该就是:MVC模式允许View层和Model层直接通讯.从图1和图2可以看到MVP和MVC的区别.

图1MVC模式中Model可以直接update data 到View层。所以当某个View的功能很复杂的时候,View和Model的耦合度可能会很高(并且在android的开发中Activity通常会充当controller&view的角色,结果Activity就很臃肿).而MVP模式就没有这个问题,View会抽象出来一系列操作UI的接口(Model层也可以),Presenter拿到的都是其他两个层级的接口来做业务逻辑的处理.这样不仅可以使View和Model之间的耦合度降低,还可以更易得进行单元测试.

                                                           图1 MVC设计模式

 


                                          图2 MVP设计模式

通过以上的分析总结MVP和MVC的区别:

MVP模式:

·View不直接与Model交互,而是通过与Presenter交互来与Model间接交互

·Presenter与View的交互是通过接口来进行的,更有利于添加单元测试

·通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑     

 MVC模式:

·View可以与Model直接交互

·Controller是基于行为的,并且可以被多个View共享

·可以负责决定显示哪个View


五、MVP设计模式的案例分析

1Model层:

StudentBean类:封装学生相关的信息,也就是封装我们的数据

在学生类中我只定义了姓名和密码两个属性进行登陆界面的实现

package com.heima.mvp.model;
/**
 * 
创建: 馥溪凝
 * 
时间: 2016-11-24 下午 03:55.
 * 描述: 封装学生相关的信息
 */
public class StudentBean {
    
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;
    }
}

 

LoginIntreface类: 学生类对外提供登陆的接口,是Model与Presenter之间沟通的桥梁

对于登陆界面来说,学生类只需要实现的一个登陆的业务逻辑,所以提供一个接口,里面只抽象出来一个登陆的方法,交给MVP模式中Presenter去处理复杂的业务逻辑

package com.heima.mvp.model;/** * 创建: 馥溪凝 * 时间: 2016-11-24 下午 03:58. * 描述: 学生类对外暴露登陆的接口 */public interface LoginInterface {    void login(StudentBean studentBean);}

 

LoginImpl类: 获取登陆过程验证的数据,以及登陆结果的回调

package com.heima.mvp.model;/** * 创建: 馥溪凝 * 时间: 2016-11-24 下午 04:01. * 描述: 实例化LoginInterface接口,通过登陆监听将结果回调给Presenter */public class LoginImpl implements LoginInterface {    public OnLoginListener mOnLoginListener;    public LoginImpl(OnLoginListener mOnLoginListener) {        this.mOnLoginListener = mOnLoginListener;    }    /**     * 登陆过程的数据判断     * @param studentBean     */    @Override    public void login(StudentBean studentBean) {        boolean status = false;        String username = studentBean.getUsername();        String password = studentBean.getPassword();        if (username != null && "qwer".equals(username)){            if (password != null && "123".equals(password)){                status = true;            }            mOnLoginListener.loginStatus(status);        }    }    /**     * 登陆是否成功的状态接口     */    public interface OnLoginListener{        void loginStatus(boolean status);    }}

 

2View层

LoginViewInterface类: 针对登陆界面抽取出处理逻辑业务相关的接口

对于登陆界面,我们需要对登陆界面进行什么操作,就在接口中定义操作的抽象方法。在本次案例中,需要获取用户名和密码,以及清空用户名和密码的简单操作和显示界面吐司的操作。

package com.heima.mvp.view;/** * 创建: 馥溪凝 * 时间: 2016-11-24 下午 04:07. * 描述: 针对View抽象出来一些列的接口 */public interface LoginViewInterface {    public String getUsername();    public String getPassword();    public void clearUsername();    public void clearPassword();    public void showMsg(String msg);}

 

LoginActivity类: 登陆界面,相当于MVP设计模式中的View,主要是处理界面相关的操作。

从上面接口的定义中,可以看出来这个时候的Activity变得非常的薄弱了,里面一点逻辑也没有了,只有单纯的显示界面了。

package com.heima.mvp.view;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import com.heima.mvp.R;import com.heima.mvp.presenter.LoginPresenter;/** *  描述: 登陆界面 *  描述: MVP设计模式中的View */public class LoginActivity extends AppCompatActivity implements LoginViewInterface{    // Used to load the 'native-lib' library on application startup.    static {        System.loadLibrary("native-lib");    }    private EditText username;    private EditText password;    private LoginPresenter loginPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);        init();    }    /**     * 初始化视图     */    private void init() {        loginPresenter = new LoginPresenter(this);        username = (EditText) findViewById(R.id.username);        password = (EditText) findViewById(R.id.password);        Button login = (Button) findViewById(R.id.login);        Button clear = (Button) findViewById(R.id.clear);        login.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                loginPresenter.login();            }        });        clear.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                loginPresenter.clear();            }        });    }    /** 获取输入用户名 */    @Override    public String getUsername() {        return username.getText().toString().trim();    }    /** 获取输入的密码 */    @Override    public String getPassword() {        return password.getText().toString().trim();    }    /** 清除用户名 */    @Override    public void clearUsername() {        username.setText("");    }    /** 清除密码 */    @Override    public void clearPassword() {        password.setText("");    }    /** 显示登陆成功的信息 */    @Override    public void showMsg(String msg) {        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();    }}

 

3Presenter层

LoginPresenter类: 处理View层和Model层相关的逻辑业务,是MVP设计模式中的Presenter。

在这个逻辑的类中,处理登陆、清空、登陆成功之后干什么等的逻辑,通过接口与listener监听沟通着View与Model,连接着里面一些复杂的业务。

package com.heima.mvp.presenter;import com.heima.mvp.model.StudentBean;import com.heima.mvp.model.LoginImpl;import com.heima.mvp.view.LoginActivity;/** * 创建: 馥溪凝 * 时间: 2016-11-24 下午 04:30. * 描述: 掌握着View和Model的所有接口,处理接口中的相关逻辑 */public class LoginPresenter{    private LoginActivity loginActivity;    private LoginImpl studnetImpl;    public LoginPresenter(final LoginActivity loginActivity) {        this.loginActivity = loginActivity;        studnetImpl = new LoginImpl(new LoginImpl.OnLoginListener() {            @Override            public void loginStatus(boolean status) { //处理登陆结果的数据逻辑                String msg;                if (status){                    msg = "登陆成功";                }else {                    msg = "登录失败";                }                loginActivity.showMsg(msg);            }        });    }    /**     * 处理登陆的业务逻辑     */    public void login() {        StudentBean studentBean = new StudentBean();        studentBean.setUsername(loginActivity.getUsername());        studentBean.setPassword(loginActivity.getPassword());        studnetImpl.login(studentBean);    }    /**     * 处理清楚的相关逻辑     */    public void clear() {        loginActivity.clearPassword();        loginActivity.clearUsername();    }}

六、耦合子interactor

     Interactor翻译过来就是耦合的意思,它在MVP设计模式中起到的其实就是一个粘合剂的角色。

        我们发现每个presenter中都持有一个或多个的interactor,而每个interactor里面就是调用了一下api接口.那为什么不在presenter中直接调用api?那是因为我们从本地数据库,或者是服务器上获取的数据封装成Model,这个Model是不能直接在界面上使用的,我们需要将这个Model转化为ViewModel成为界面使用的数据。简单点说,就是我们从服务器或者数据库获取的数据封装成JavaBean之后,需要再一次进行转化成View中需要的JavaBean,而这个过程就叫interactor。

       在presenter中,Presenter实现Interactor的回调接口,可以接收到ViewModel的实例,此时它在回调函数里面只需要将接收到的ViewModel绑定的View上面即可。可以看到,在这个过程中Presenter并没有触及到具体的实现,只是把View 和 ViewModel进行了绑定而已。当然你也可以把数据逻辑写在Presenter,但是Interactor就不存在了。

其实Interactor的存在,是为了Presenter更加的简化,当数据逻辑较为复杂的时候,interactor就会显示出它的价值了,因为interactor可以被复用,复用就会使得代码更加的简洁,使得数据的处理逻辑不会复杂。

0 0