MVC和MVP在app中的对比分析

为了解决逻辑处理和UI视图的松散耦合,MVC和MVP的架构模式在很多App中使用比较广泛。

那什么是MVP呢?它又和我们常常听到的MVC有什么关系了以及区别呢?


MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。

在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,及View。所以,在MVC模型里,Model不依赖于View,但是 View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

MVP如何解决MVC的问题?

在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具 体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,即重用! 不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试—而不需要使用自动化的测试工具。 我们甚至可以在Model和View都没有完成时候,就可以通过编写Mock Object(即实现了Model和View的接口,但没有具体的内容的)来测试Presenter的逻辑。 在MVP里,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层。因此就有人提出了Presenter First的设计模式,就是根据User Story来首先设计和开发Presenter。在这个过程中,View是很简单的,能够把信息显示清楚就可以了。在后面,根据需要再随便更改View, 而对Presenter没有任何的影响了。 如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,就可以在View和Presenter之间放置一个Adapter。由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之 间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。 在MVP模式里,View只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model— 这就是与MVC很大的不同之处。

MVP的优点:

1、模型与视图完全分离,我们可以修改视图而不影响模型;
2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。

使用方法

1、建立bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserBean {
     private String mFirstName;
     private String mLastName;
     public UserBean(String firstName, String lastName) {
         this . mFirstName = firstName;
         this . mLastName = lastName;
     }
     public String getFirstName() {
         return  mFirstName;
     }
     public String getLastName() {
         return  mLastName;
     }
}

2、建立model接口(处理业务逻辑,这里指数据读写)

1
2
3
4
5
6
7
public interface IUserModel {
     void setID(int id);
     void setFirstName(String firstName);
     void setLastName(String lastName);
     int getID();
     UserBean load(int id); // 通过id读取user信息,返回一个UserBean
}

3、建立view接口(更新ui中的view状态),这里列出需要操作当前view的方法

1
2
3
4
5
6
7
public interface IUserView {
     int getID();
     String getFristName();
     String getLastName();
     void setFirstName(String firstName);
     void setLastName(String lastName);
}

4、建立presenter(主导器,通过iView和iModel接口操作model和view),activity可以把所有逻辑给presenter处理,这样java逻辑就从手机的activity中分离出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserPresenter {
     private IUserView mUserView;
     private IUserModel mUserModel;
     public UserPresenter(IUserView view) {
         mUserView = view;
         mUserModel =  new  UserModel();
     }
     public void saveUser( int id, String firstName, String lastName) {
         mUserModel.setID(id);
         mUserModel.setFirstName(firstName);
         mUserModel.setLastName(lastName);
     }
     public void loadUser( int id) {
         UserBean user = mUserModel.load(id);
         mUserView.setFirstName(user.getFirstName());  // 通过调用IUserView的方法来更新显示
         mUserView.setLastName(user.getLastName());
     }
}

结束语

MVP主要解决就是把逻辑层抽出来成P层,要是遇到需求逻辑上的更改就可以只需要修改P层了或者遇到逻辑上的大概我们可以直接从写一个P也可以,很 多开发人员把所有的东西都写在了Activity/Fragment里面这样一来遇到频繁改需求或者逻辑越来越复杂的时候,Activity /Fragment里面就会出现过多的混杂逻辑导致出错,所以MVP模式对于APP来对控制逻辑和UI的解耦来说是一个不错的选择!

=======================================================================================

一.概述


MVP(Model-View-Presenter) 是总所周知MVC模式的一个演变,他们的主要目的都是划分模块职责,降低模块耦合,易测试,提高代码复用,这里主要针对Android平台来简单分析MVP.


1.层级责任

Model:       负责数据的检索,持久化等操作

View:         负责UI的绘制和用户的交互

Presenter: 作为Model和View的中间协调部分,负责两者之间的业务逻辑处理


2.与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模式


3.MVP的优缺点

优点:降低耦合,层级职责更明显,易于单元测试

缺点:造成类数量爆炸,代码复杂度和学习成本高,在某些场景下presenter的复用会产生接口冗余



二. MVP简单的实例

使用MVP 写一个简单的登陆功能,主页就两个按钮:Login 和 Clear

1.项目结构


  


2.Model层

包含有一个实体UserBean用来承载数据和UserBiz来对登陆数据判断

[java]  view plain  copy
  1. public class UserBean {  
  2.     private String username;  
  3.     private String password;  
  4.   
  5.     public String getUsername() {  
  6.         return username;  
  7.     }  
  8.   
  9.     public void setUsername(String username) {  
  10.         this.username = username;  
  11.     }  
  12.   
  13.     public String getPassword() {  
  14.         return password;  
  15.     }  
  16.   
  17.     public void setPassword(String password) {  
  18.         this.password = password;  
  19.     }  
  20. }  


UserBiz通过抽象出一个接口


[java]  view plain  copy
  1. public interface UserBiz {  
  2.     public void login(UserBean login);  
  3. }  

UserBizImpl实例化接口,并且通过登陆监听将结果回调给Presenter

[java]  view plain  copy
  1. public class UsrBizImpl implements UserBiz{  
  2.     private OnLoginListener listener;  
  3.   
  4.     public UsrBizImpl(OnLoginListener listener){  
  5.         this.listener = listener;  
  6.     }  
  7.   
  8.     @Override  
  9.     public void login(UserBean login) {  
  10.         boolean status = false;  
  11.         String username,password;  
  12.         username = login.getUsername();  
  13.         password = login.getPassword();  
  14.         if (username != null && "asdf".equals(username))  
  15.             if (password != null && "123".equals(password))  
  16.                 status = true;  
  17.         listener.loginStatus(status);  
  18.     }  
  19. }  

3.View层

把View层针对控件操作抽象出来一些列的接口

[java]  view plain  copy
  1. public interface LoginView {  
  2.     public String getUsername();  
  3.     public String getPassword();  
  4.     public void clearUsername();  
  5.     public void clearPassword();  
  6.     public void showMsg(String msg);  
  7. }  

在Activity里面实现该接口的控件操作,并且初始化Presenter,这是可以看到Activity里面没有逻辑处理,只是对UI的控件进行数据或者行为的操作,所有的动作都是有Presenter的接口来实现,这样在项目里面会极大得精简Activity的体积.

[java]  view plain  copy
  1. public class LoginActivity extends Activity implements LoginView{  
  2.     private EditText username, password;  
  3.     private Button login, clear;  
  4.     private LoginPresenter loginPresenter;  
  5.   
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_login);  
  10.         init();  
  11.     }  
  12.   
  13.     private void init(){  
  14.         loginPresenter = new LoginPresenterImpl(this);  
  15.         username = (EditText) findViewById(R.id.username);  
  16.         password = (EditText) findViewById(R.id.pass);  
  17.         login = (Button) findViewById(R.id.login);  
  18.         clear = (Button) findViewById(R.id.clear);  
  19.         login.setOnClickListener(new View.OnClickListener() {  
  20.             @Override  
  21.             public void onClick(View view) {  
  22.                 loginPresenter.login();  
  23.             }  
  24.         });  
  25.   
  26.         clear.setOnClickListener(new View.OnClickListener() {  
  27.             @Override  
  28.             public void onClick(View view) {  
  29.                 loginPresenter.clear();  
  30.             }  
  31.         });  
  32.     }  
  33.   
  34.     @Override  
  35.     public String getUsername() {  
  36.         return username.getText().toString();  
  37.     }  
  38.   
  39.     @Override  
  40.     public String getPassword() {  
  41.         return password.getText().toString();  
  42.     }  
  43.   
  44.     @Override  
  45.     public void clearUsername() {  
  46.         username.setText("");  
  47.     }  
  48.   
  49.     @Override  
  50.     public void clearPassword() {  
  51.         password.setText("");  
  52.     }  
  53.   
  54.     @Override  
  55.     public void showMsg(String msg) {  
  56.         Toast.makeText(this, msg, Toast.LENGTH_LONG).show();  
  57.     }  
  58. }  

4.Presenter层

在Presenter层里面,Presenter掌握着View和Model的所有接口,Presenter就可以根据不同的业务逻辑通过MV两层的接口来实现特定的功能,让M和V独立出来.

[java]  view plain  copy
  1. public class LoginPresenterImpl implements LoginPresenter, OnLoginListener{  
  2.     private UserBiz userBiz;  
  3.     private LoginView loginView;  
  4.   
  5.     public LoginPresenterImpl(LoginView loginView){  
  6.         this.loginView = loginView;  
  7.         userBiz = new UsrBizImpl(this);  
  8.     }  
  9.   
  10.     @Override  
  11.     public void login() {  
  12.         UserBean login = new UserBean();  
  13.         login.setUsername(loginView.getUsername());  
  14.         login.setPassword(loginView.getPassword());  
  15.         userBiz.login(login);  
  16.     }  
  17.   
  18.     @Override  
  19.     public void clear() {  
  20.         loginView.clearPassword();  
  21.         loginView.clearUsername();  
  22.     }  
  23.   
  24.     @Override  
  25.     public void loginStatus(boolean status) {  
  26.         String msg;  
  27.         if (status)  
  28.             msg = "login succeed";  
  29.         else  
  30.             msg = "login failed";  
  31.         loginView.showMsg(msg);  
  32.     }  
  33. }  

5.Demo下载地址 

优快云下载


三.总结

简单得用了下MVP,也有跟朋友讨论了一下,好多人都说这个看着挺不错的,但是用着很麻烦。确实现在Android项目用MVP的不是占多数,带着一些疑惑楼主就想去了解一下android原生程序里面是用的什么风格的,之前也有看过一些android源码,但是都是断断续续的,也好久没有写过博客了,本着对技术的热爱,计划重新开启撸android源码的计划(从Android原生的系统程序到framework再一路向下),现在希望自己能够坚持下来,并且产出一个博客的系列和大家一起分享和成长.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值