MVP模式分析

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*/@Overridepublic 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;@Overrideprotected 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() {@Overridepublic void onClick(View v) {loginPresenter.login();}});clear.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {loginPresenter.clear();}});}/** 获取输入用户名 */@Overridepublic String getUsername() {return username.getText().toString().trim();}/** 获取输入的密码 */@Overridepublic String getPassword() {return password.getText().toString().trim();}/** 清除用户名 */@Overridepublic void clearUsername() {username.setText("");}/** 清除密码 */@Overridepublic void clearPassword() {password.setText("");}/** 显示登陆成功的信息 */@Overridepublic 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() {@Overridepublic 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可以被复用,复用就会使得代码更加的简洁,使得数据的处理逻辑不会复杂。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部