MVC MVP MVVM 分别是什么?
MVC
及其优缺点
答案参考自:
概念
MVC全名是Model-View-Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范。
MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。更好的调节M和V的搭配。
MVC是一种框架模式,说到底是一种框架,而不是一种设计模式,框架通常是代码重用,而设计模式是设计重用,而架构则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。
优点
分层,结构清晰,耦合性低,大型项目代码的复用性得到极大的提高,开发人员分工明确,提高了开发的效率,维护方便,降低了维护成本。
缺点
简单的小型项目,使用MVC设计反而会降低开发效率,层和层虽然相互分离,但是之间关联性太强,没有做到独立的重用。
MVP
及其优缺点
答案参考自:
概念
实际上按照代码在 App 中所处位置,描述为 VPM 更合适,即 View -> Presenter -> Model:
这个架构的核心就是 View 与 Presenter 都被抽象成了接口,是面向接口编程的一个实践。因为面向接口,所以实现了依赖隔离,即无需知道具体的 Class 类型。
优点
- 模块职责划分明显,层次清晰,接口功能清晰,遵循了单一职责类的设计原则,提升了代码的可维护性.
- 降低耦合度,Model层和View层分离,解耦.修改View而不影响Model.
- 功能复用度高,方便.一个Presenter可以复用于多个View,而不用更改Presenter的逻辑.
- 有利于测试驱动开发,以前的Android开发是难以进行单元测试.
- 代码灵活性,如果后台接口还未写好,但已知返回数据类型的情况下,完全可以写出此接口完整的功能.
缺点
- 其实这并不是 MVP 架构的痛点,而是整个 Android App 开发的痛点,那就是对 UI 的操作必须在 Activity 与 Fragment 的生命周期之内,更细致一点,最好在
onStart()
之后onPause()
之前,否则极其容易出现各种异常。而 MVP 架构中,Presenter 对 Activity 与 Fragment 的生命周期是无感知的,所以我们需要手动添加相应的生命周期方法,并进行特殊处理,以避免出现异常或内存泄露。 - MVP中接口过多.
- 每一个功能,相比于MVC要多写好几个文件.
- 如果某一个界面中需要请求多个服务器接口,这个界面文件中会实现很多的回调接口,导致代码繁杂.
- 如果更改了数据源和请求中参数,会导致更多的代码修改.
额外的代码复杂度及学习成本. - 由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。
MVVM
及其优缺点
答案参考自:
概念
View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
在MVVM中,数据是核心,由于ViewModel与View之间的双向绑定,操作了ViewModel中的数据,就会同步到DOM,我们透过DOM事件监控用户对DOM的改动,也会同步到ViewModel。
MVVM 架构相对复杂,核心是 LifecycleOwner、LifecycleObserver、LifecycleRegistry 组件,在此之上,Google 还开发了 DataBinding、ViewModel、LiveData 以实现完整的 MVVM 架构。相关组件已收纳至 JetPack Architecture 中。
这个架构的核心就是 ViewModel 和 LiveData。ViewModel 的作用是保证当设备因配置改变而重新创建 FragmentActivity(目前 ViewModel 仅支持 FragmentActivity 和 Fragment) 时,数据也不会丢失。LiveData 的作用是保证只在 FragmentActivity 或 Fragment 的生命周期状态为 [onStarted, onResumed] 时,回调 onChanged(T data),所以我们可以在 onChanged() 中安全的更新 UI。下面简单介绍源码中是如何实现的:
优点
ViewModel:因设备配置改变导致 Activity 重建时,无需从 Model 中再次加载数据,减少了 IO 操作
LiveData:更新 UI 时,不用再关注生命周期问题
Data Binding: 可以有效减少模板代码的编写,而且目前已经支持双向绑定 (注意:不是所有的 UI 都需要使用 Data Binding,虽然通过 @BindingAdapter 我们真的可以“为所欲为”,最好还是只用于需要绑定 Bean 类的布局)
缺点
- LiveData 本身是没有 public 方法的,所以我们应该使用其子类 MutableLiveData。这样设计,我们就可以在 Model 中使用 MutableLiveData,在 ViewModel 中,只对 View 提供 LiveData,避免 View 去更新 LiveData。
MVP
如何防止内存泄漏
在
BasePresenter
中使用对View
的弱引用1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public abstract class BasePresenter<M extends BaseModel, V extends BaseView, CONTRACT> {
protected M m;
protected WeakReference<V> weakReference;
public BasePresenter() {
this.m = getModel();
}
protected void bindView(V v) {
weakReference = new WeakReference<>(v);
}
protected void unbindView() {
if (weakReference != null) {
weakReference.clear();
weakReference = null;
System.gc();
}
}
protected V getView() {
if (weakReference != null)
return weakReference.get();
return null;
}
protected abstract CONTRACT getContract();
protected abstract M getModel();
}在
BaseView
中onCreate
和onDestory
方法中主动绑定和解绑Presenter
,防止内存泄漏。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public abstract class BaseView<P extends BasePresenter, CONTRACT> extends Activity {
protected P p;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
p = getPresenter();
p.bindView(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
p.unbindView();
}
protected abstract P getPresenter();
protected abstract CONTRACT getContract();
}
TODO
- MVP如何管理Presenter的生命周期,何时取消网络请求