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可以被复用,复用就会使得代码更加的简洁,使得数据的处理逻辑不会复杂。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
