MVC与MVP对比

MVC模式

MVC的全称是Model-View-Controller,模型-视图-控制器。MVC是一种框架模式而非设计模式。GOF把MVC看作是三种设计模式——观察者模式、策略模式与组合模式的合体,核心是观察者模式,也就是一个基于发布/订阅者模型的框架。

![enter description here][1]

在Android开发中,View对应的是各个布局文件,Controller对应的是Activity,而Model层主要是对应于从本地或网络获取数据、处理数据等(更符合实际的说法应该是,View与Controller层都是Activity)。
用户与视图交互,视图接收并反馈用户的动作;视图把用户的请求传给相应的控制器,由控制器决定调用哪个模型,然后由模型调用相应的业务逻辑对用户请求进行加工处理,如果需要返回数据,模型会把相应的数据返回给控制器,由控制器调用相应的视图,最终由视图格式化和渲染返回的数据,对于返回的数据完全可以增加用户体验效果展现给用户。
一个模型可以有多个视图,一个视图可以有多个控制器,一个控制器也可以有多个模型。

MVC的分层好处在于:
* 可以在不依赖于业务逻辑的情况下专注于视图设计
* 让程序的测试更容易
* 简化了分组开发。不同的开发人员可以同时开发视图、控制器逻辑和业务逻辑。

可以看到,MVC的主要目的是为了实现视图和数据分离(个人感觉在Android中实际上并没有实现)。

关于MVC在Android中的对应关系,网上的资料比较混乱,因为作为V层的布局文件,能做的事情却非常有限;而作为C层的Activity,却又具有操作UI的功能,也做了许多V层的事情。个人比较认同的是Activity同时充当V层与C层,因为Activity还负责了展示布局、增添View等操作,这就使得Activity既当爹又当妈。这显然不符合软件设计原则中的“单一职责”原则,当业务比较复杂的时候,会导致Activity的过于臃肿,动辄几千行代码。


MVP模式

MVC中Controller对应的是Activity,但Activity不仅做了C层该做的事情比如派发各类事件,还做了V层的一些UI操作事情,Activity作为C层是非常重的,各层次之间的耦合情况也是比较严重,不方便做单元测试,同时当业务复杂时Activity中的代码量太大,开发维护太难。
这个时候MVC的进化版MVP就诞生了。MVP全称是Model-View-Presenter。在MVP中,
* M层依旧负责数据的获取、处理
* Activity/Fragment充当View层,负责创建/更新视图
* P层则专门负则具体的业务逻辑

![enter description here][2]

用户与V层交互,V层根据用户的操作调用P层的逻辑,P层接收V层调用,执行具体的业务逻辑并根据不同的业务逻辑调用不同的Model进行数据操作,当M层执行完数据操作之后通知P层,P层再通过接口回调通知V层进行视图更新。

这样Model、View、Presenter三层都相对独立了,Activity/Fragment也不会像MVC中那样既当爹又当妈,而是专注负则视图操作。以此真正达到了奖Model层与View层解耦的目的。

==MVP的好处之一在于,方便进行单元测试。以往在MVC中,由于Activity同时充当C、V,许多代码都写在Activity中,当要对业务逻辑代码进行测试的时候,必须要部署应用到手机/模拟器上,耗费大量时间。在MVP中,V层与P层独立,它们之间的交互通过interface进行(接口回调),意味着我们可以自定义类实现这个interface来模拟Activity的行为,来进行对P层的单元测试,节省了大量的应用部署时间。==

在实习期间开发的项目,使用的就是MVP模式。使用MVP的最大感受就是Activity中终于不会充斥着大量的业务逻辑代码,而是专注负则UI展示,顿时清爽了,要进行增改都容易了好多。


MVC与MVP的对比
  • MVP中View与Model并不直接交互,而MVC中View与Model是可以直接交互的
  • Presenter与View的交互是通过接口实现的,更有利于进行单元测试
  • 在MVP中Activity代码不臃肿
  • 在MVP中,Presenter可以用于多个视图,但是在MVC中作为Controller的Activity就不行
MVP优点
  • 降低耦合度
  • 模块职责划分明显
  • 利于单元测试
  • 代码复用
  • 便于协同开发
MVP的缺点
  • 多出了许多类、接口,解决方法:
    • 对于逻辑简单的页面可以不适用Presenter,直接在V层处理。在P层中如果不需要处理数据,也可以不适用Model
    • P与V层接口可以复用,因此不需要每个Activity/Fragment都划分一套MVP,可以几个Activity/Fragment使用同一个Presenter/V层接口,当然也可以一个Activity/Fragment根据不同需求持有多个不同类型的Presenter/实现多个V层接口。
  • 由于V层接口可以多次复用,会导致当业务需求变化时,实现了V层接口的Activity/Fragment都需要改动,解决方法:
    • 只能在开发阶段尽量依照面向对象设计中的“开闭原则(OCP)”进行开发,即是对扩展开放,对修改关闭。
  • Presenter持有Activity引用导致Activity销毁后内存无法被回收,出现内存泄漏,解决方法:
    • 是在Presenter中使用弱引用持有对Activity的引用,具体方法是
      1. 定义一个Presenter基类,持有View的弱引用,并在View的onCreate中进行attach,在view的onDestroy中detach
 //V:表示任意view类型,一般是IView
public class BasePresenter<V> {
private WeakReference<V> weakRefView;
public void attach(V view){
        weakRefView = new WeakReference<V>(view);
 }

public void detach() {
    if(isAttach()) {
        weakRefView.clear();
        weakRefView = null;
    }
}
public V obtainView(){
    return isAttach()?weakRefView.get():null;
}

protected boolean isAttach() {
    return weakRefView != null &&
            weakRefView.get() != null;
 }
}

2 定义一个Activity基类,处理与BasePresenter之间的引用关系(值得再研究,因为这样做的话一个Activity就只能自动处理一个Presenter了)

public abstract class BaseActivity<V,P extends BasePresenter<V>> 
extends Activity{

protected P mPresenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mPresenter = createPresenter();
    mPresenter.attach((V)this);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mPresenter.detach();
}

public abstract P createPresenter();

后话

看了这么久MVC、MVP的资料,网上针对它们的具体实现各有不同,一开始还很纠结到底哪个是对的,想着找一些权威资料。后来想通了MVC、MVP这些框架模式不过都是为了解决我们开发中遇到的结构混乱、耦合度高的问题,MVP纵然能实现更好地解耦,但对于简单的页面/业务逻辑还死守标准的MVP模式,徒增一堆类/接口,反倒降低了开发效率。使用框架模式的目的就是为了更好地开发,不能本末倒置增加工作量来满足所谓的标准。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值