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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2、MVC设计图解释

到底上面列出的设计图哪个才是对的。其实都是对的。为什么这么说呢,这得从mvc的发展说起。 MVC框架模式最早由Trygve Reenskaug 于1978年在Smalltalk-80系统上首次提出。经过了这么多年的发展,当然会演变出不同的版本,但核心没变依旧还是三层模型Model-View-Control。

3、MVC三层之间的关系

箭头→代表的是一种事件流向,并不一定要持有对方,比如上图中model→view的事件流向,view可以通过注册监听器的形式得到model发来的事件。在设计中model view controller之间如果要通讯,尽量设计成不直接持有,这样方便复用。也符合mvc的设计初衷 在android中三者对应的关系如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

视图层(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不太好彻底解耦,但是在一定程度上我们还是可以解耦的。 Talk is cheap. Show me the code. 扯了这么多,我们来看点代码。

4、MVC sample

通过代码来看下,mvc在android中的实现

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结构很简单,这里介绍下其中的关键代码

public interface BaseModel {
void onDestroy();
}

BaseModel顾名思义就是所有业务逻辑model的父类,这里的onDestroy()方法用于跟activity或者fragment生命周期同步,在destroy做一些销毁操作

public interface Callback1 {
void onCallBack(T t);
}
public interface Callback2<T,P> {
void onCallBack(T t,P p);
}

Callback是根据View或者Controller调用Model时回调的参数个数选择使用

public class SampleModel implements BaseModel{

public void getUserInfo(String uid,Callback1 callback)
{

UserInfo userInfo= new HttpUtil().get(uid);
callback.onCallBack(userInfo);

}

@Override
public void onDestroy() {

}

public class UserInfo
{
private int age;
private String name;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
}

SampleModel是我们业务逻辑的具体实现

public class SampleActivity extends AppCompatActivity {
private SampleModel sampleModel;
Button button;
EditText textView;
TextView tvAge,tvName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
sampleModel=new SampleModel();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getUserInfo(textView.getText().toString());
}
});

}

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

/**

  • 获取用户信息
  • @param uid
    */
    private void getUserInfo(String uid)
    {
    sampleModel.getUserInfo(uid, new Callback1<SampleModel.UserInfo>() {
    @Override
    public void onCallBack(SampleModel.UserInfo userInfo) {
    setDataToView(userInfo);
    }
    });
    }

/**

  • 设置用户信息到view
    */
    private void setDataToView(SampleModel.UserInfo userInfo)
    {
    tvAge.setText(userInfo.getAge());
    tvName.setText(userInfo.getName());
    }

}

前面说了Activity充当View和Controller,但是我们依然要区分到底哪一部分是View的操作,哪一部分是Controller的操作。 我们分析下事件的流向
button点击事件的触发:View→Controller 获取用户信息事件的触发:Controller→Model 绑定用户信息到View:Controller→View 至此MVC就讲完了

5、MVC总结

我们这里根据sample来总结下:

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

MVP

1、MVP说明

MVP跟MVC很相像,文章开头列出了很多种MVC的设计图,所以根据MVC的发展来看,我们把MVP当成MVC来看也不为过,因为MVP也是三层,唯一的差别是Model和View之间不进行通讯,都是通过Presenter完成。 前面介绍MVC的时候提到了算是致命缺点吧,在android中由于activity(god object)的存在,Controller和View很难做到完全解耦。但在MVP中就可以很好的解决这个问题 看下MVP的设计图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一般情况下就这两种

2、MVP Sample

依然延续MVC的例子,修改下结构通过MVP去实现,看下项目代码结构:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

callback,http包下内容基本一致,主要看下不同的地方

public interface BasePresenter {
void onDestroy();
}

BasePresenter类似于MVC中的BaseModel,主要负责业务逻辑的实现。我们这里没有把业务逻辑放在Model里去实现,当然把主要业务逻辑放在Model中去实现也是可以的。google的MVP实现方案是把业务逻辑放在presenter中,弱化Model,我们这里也是这样做的。

public interface BaseView

{
void setPresenter(P presenter);
}

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

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
{
void setDataToView(SampleModel.UserInfo userInfo);
}
}

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

public class SampleActivity extends AppCompatActivity implements SampleContract.View{
private SampleContract.Presenter mPresenter;
Button button;
EditText textView;
TextView tvAge,tvName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
setPresenter(new SampleContract.Presenter());

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPresenter.getUserInfo(textView.getText().toString(), new Callback1<SampleModel.UserInfo>() {
@Override
public void onCallBack(SampleModel.UserInfo userInfo) {
setDataToView(userInfo);
}
});
}
});

}

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

@Override
public void setDataToView(SampleModel.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的引用。

3、MVP总结

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

MVVM

1、MVVM说明

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

2、MVVM与DataBinding的关系

一句话表述就是,MVVM是一种思想,DataBinding是谷歌推出的方便实现MVVM的工具。在google推出DataBinding之前,因为xml layout功能较弱,想实现MVVM非常困难。而DataBinding的出现可以让我们很方便的实现MVVM。

3、DataBinding简介

DataBinding是实现视图和数据双向绑定的工具,这里简单介绍下基本用法,详细用法可以参照官方:https://developer.android.com/topic/libraries/data-binding/ 启用DataBinding,只需要在gradle文件中添加如下代码:

android {
dataBinding{
enabled true
}
}

通过DataBindingUtil可以动态生成一个ViewDataBinding的子类,类名以layout文件名大写加Binding组成,如:

ActivitySampleMvvmBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sample_mvvm);

在layout中需要我们配置,每个控件绑定的实体对象,以layout进行包裹,data中配置变量名和类型,通过@{}或@={}的方式进行引用,其中@={}的方式表示双向绑定。目前支持双向绑定的控件如下:

AbsListView android:selectedItemPosition CalendarView android:date CompoundButton android:checked DatePicker android:year, android:month, android:day NumberPicker android:value RadioGroup android:checkedButton RatingBar android:rating SeekBar android:progress TabHost android:currentTab TextView android:text TimePicker android:hour, android:minute

<?xml version="1.0" encoding="utf-8"?>

<TextView
android:id=“@+id/tv_name”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”

文末

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,可以来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。

这里放上一部分我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,可以来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。

这里放上一部分我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家

[外链图片转存中…(img-2DVWph4v-1715852887519)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值