MVC MVP MVVM

MVC

负责图

视图层(View)对应 xml 布局文件和 java 代码动态 View 部分。

控制层(Controller)MVC 中 Android 的控制层是由 Activity 来承担,Activity 本来主要是作为初始化页面,展示数据的操作,但是因为 XML 视图功能太弱,所以 Activity 既要负责视图的显示,又要加入控制逻辑,承担的功能过多。

模型层(Model)针对业务模型,建立的数据结构和相关的类,它主要负责网络请求,数据库处理,I/O 的数据。

由于 Android 中有个 God Object 的存在,Activity 再加上 Android 中 XML 布局的功能性太弱,所以 Activity 承担了绝大部分的工作。所以在 Android 中 MVC 更像是这种形式:

因为 Activity 扮演了 Controller 和 View 的工作,所以 Controller 和 View 不太好彻底解耦,但在一定程度上还是可以解耦的。Activity 充当了 View 和 Controller,我们仍要区分到底哪一部分是 View 的操作,哪一部分是 Controller 的操作。事件的流向:View -> Controller 获取用户信息事件的触发:Controller -> Model 绑定用户信息到 View:Controller -> View

总结

  • 具有一定的分层,model 彻底解耦,controller 和 view 并没有解耦
  • 层与层之间的交互尽量使用回调或者去使用消息机制去完成,尽量避免直接持有
  • controller 和 view 在 Android 中无法做到彻底分离,但在代码逻辑层面一定要分清
  • 业务逻辑被放置在 model 层,能够更好的复用和修改增加业务

MVP

mvp

1
2
3
public interface BasePresenter{
void onDestroy();
}

BasePresenter 类似于 MVC 中 BaseModel,主要负责业务逻辑的实现。Google 的 MVP 实现方案是把业务逻辑放在 presenter 中,弱化 Model。

1
2
3
public interface BaseView<P extends BasePresenter>{
void setPresenter(P presenter);
}

BaseView 是所有 View 的父类,将 Android 中的 View 抽象出来,只有跟 View 相关的操作都由 BaseView 的实现类去完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SampleContract{
public static class Presenter implements BasePresenter{
public void getUserInfo(String uid, Callback1<SampleModel.UserInfo> callback){
SampleModel.UserInfo userInfo = new HttpUtil<SampleModel.UserInfo>().get(uid);
callback.onCallBack(userInfo);
}

@Override
public void onDestroy(){

}
}
public interface View extends BaseView<Presenter>{
void setDataToView(SampleModel.UserInfo userInfo);
}
}

Contract 契约类这是 Google MVP 与其他实现方式的又一个不同,契约类用于定义同一个界面的 View 的接口和 Presenter 的具体实现。好处是通过规范的方法命名和注释可以清晰的看到整个页面的逻辑。

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
29
30
31
32
33
34
35
36
public class SampleActivity extends Activity implements SampleContract.View{
private SampleContract.Presenter mPresenter;

@Override
protected void onCreate(Bundle saved InstanceState){
...
setPresenter(new SampleContract.Presenter());
}

@OnClick(R.id.btn)
public void click(){
mPresenter.getUserInfo("data", new Callback1<SampleModel.UserInfo>(){
@Override
public void onCallback(SampleModel.UserInfo userInfo){
setDataToView(userInfo);
}
});
}

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

@Overried
public void setDataToView(SampleMpdel.UserInfo userInfo){
tvAge.setText(userInfo.getAge());
tvName.setText(userInfo.getName());
}

@Override
public void setPresenter(SampleContract.Presenter presenter){
mPresenter = presenter;
}
}

这里的 SampleActivity 实现了 SampleContract.View 只是作为 View 存在的。虽然看起来,跟 MVC 中的实现很类似,但却有本质的区别。mPresenter 为 Model 和 View 之间交互的桥梁。Presenter 跟 View 相互持有,这里 SampleActivity 实现了 SampleContract.View,mPresenter 作为 SampleActivity 的成员变量, SampleActivity 当然持有 mPresenter,由于 mPresenter 是非静态的成员变量,因此默认持有 SampleActivity 的引用。

总结

通过引入接口 BaseView,让相应的视图组件如 Activity,Fragment 去实现 BaseView,实现了视图层的独立,通过中间件 Presenter 实现了 Model 和 View 的完全解耦。MVP 彻底解决了 MVC 中 View 和 Controller 过分交织的问题。但是随着业务逻辑的增加,一个页面可能会非常复杂,UI 的改变是非常多,会有非常多的 case,这样就会造成 View 的接口会很庞大。

MVVM

MVP 中随着业务逻辑的增加,UI 的改变多的情况下,会有非常多的跟 UI 相关的 case,这样就会造成 View 的接口会很庞大。而 MVVM 就解决了这个问题,通过双向绑定的机制,实现数据和 UI 内容,只要想改其中一方,另一方都能够及时更新的一种设计理念,这样就省去了很多在 View 层中写很多 case 的情况,只需要改变数据就行。

MVVM

一般情况下就这两种情况,这看起来跟 MVP 好像没啥差别,其实区别还是挺大的。在 MVP 中 View 和 Presenter 要相互持有,方便调用对方;而在 MVVM 中 View 和 Model 通过 Binding 进行关联,他们之前的关系处理通过 DataBinding 完成。

MVVM 是一种思想,DataBinding 是谷歌推出的方便实现 MVVM 的工具

总结

看起来 MVVM 很好地解决了 MVC 和 MVP 的不足,但是由于数据和视图的双向绑定,导致出现问题时不太好定位来源,有可能数据问题导致,也有可能业务逻辑中对视图属性的修改导致。如果项目中打算用 MVVM 的话可以考虑使用官方的架构组件 ViewModel、LiveData、DataBinding 去实现 MVVM

如何选择

  1. 项目简单,没有什么复杂性,未来改动也不大的话,那就不要用设计模式或者架构方法,只需要将每个模块封装好,方便调用即可,不要为了使用设计模式或架构方法而使用。
  2. 对于偏向展示型 App,绝大多数业务逻辑都在后端,App 主要功能就是展示数据、交互等,建议使用 MVVM。
  3. 对于工具类或者需要写很多业务逻辑 app,使用 MVP 或者 MVVM 都可。
  4. 如果想通过一个项目去学习架构和设计模式,建议使用 MVC 然后在此基础上慢慢挖掘改进。最后你可能发现,改进的最终结果可能就变成了 MVP,MVVM。

引用参考

MVC、MVP、MVVM,我到底该怎么选?