日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

發布時間:2025/4/16 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MVC、MVP、MVVM,我到底该怎么选? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

MVC、MVP、MVVM是我們工作和面試中都比較重要的一塊,但很多時候我們卻有點迷惑。比如看了好多篇文章都搞不懂MVC到底是個啥本來想寫個MVP寫著寫著就變成MVC了,到底Databing和MVVM之間有啥見不得人的關系。本篇文章主要從發展的角度來介紹,如mvp,mvvm的出現都是為了解決前者的哪些問題。如果你有同樣的疑問,本篇文章可能會給你帶來一點收獲。但是架構和設計模式相對來說不是那么容易捉摸透的東西,很多需要經過實踐才能體會,另外由于本人水平有限,如果寫的不對或者不嚴謹的地方,請不要打我。

MVC

可能由于MVP、MVVM的興起,MVC在android中的應用變得越來越少了,但MVC是基礎,理解好MVC才能更好的理解MVP,MVVM。因為后兩種都是基于MVC發展而來的。

1、MVC眼花繚亂設計圖

我們從網上搜索mvc相關資料時,如果你多看幾篇文章的話可能會發現,好像他們介紹的設計圖都不太一樣,這里羅列了大部分的設計圖

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<T> {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<UserInfo> callback){UserInfo userInfo= new HttpUtil<UserInfo>().get(uid);callback.onCallBack(userInfo);}@Overridepublic 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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sample);sampleModel=new SampleModel();button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {getUserInfo(textView.getText().toString());}});}@Overrideprotected void onDestroy() {super.onDestroy();sampleModel.onDestroy();}/*** 獲取用戶信息* @param uid*/private void getUserInfo(String uid){sampleModel.getUserInfo(uid, new Callback1<SampleModel.UserInfo>() {@Overridepublic 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<P extends BasePresenter> {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);}@Overridepublic void onDestroy() {}}public interface View extends BaseView<Presenter>{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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sample);setPresenter(new SampleContract.Presenter());button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mPresenter.getUserInfo(textView.getText().toString(), new Callback1<SampleModel.UserInfo>() {@Overridepublic void onCallBack(SampleModel.UserInfo userInfo) {setDataToView(userInfo);}});}});}@Overrideprotected void onDestroy() {super.onDestroy();mPresenter.onDestroy();}@Overridepublic void setDataToView(SampleModel.UserInfo userInfo) {tvAge.setText(userInfo.getAge());tvName.setText(userInfo.getName());}@Overridepublic 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是實現視圖和數據雙向綁定的工具,這里簡單介紹下基本用法,詳細用法可以參照官方:developer.android.com/topic/libra… 啟用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"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"><data ><variablename="user"type="com.androfarmer.mvvm.model.SampleModel.UserInfo"></variable></data> <LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@={user.name}"/><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@={user.age+``}"/></LinearLayout> </layout>復制代碼

以上為具體在xml的用法展示:

public static class UserInfo extends BaseObservable{private int age;private String name;@Bindablepublic int getAge() {return age;}public void setAge(int age) {this.age = age;notifyPropertyChanged(BR.age);}@Bindablepublic String getName() {return name;}public void setName(String name) {this.name = name;notifyPropertyChanged(BR.name);}}復制代碼

為了實現雙向綁定還需要對數據實體類做處理,繼承BaseObservable,對讀寫方法做@Bindable和notifyPropertyChanged處理。還可以直接使用官方提供的泛型可觀察對象 ObservableField,比如: private ObservableField name=new ObservableField<>();

4、MVVM Sample

MVVM中跟MVP中一樣,將三層劃分的很清楚,Activity和xml layout充當View,ViewModel處理業務邏輯以及獲取數據,弱化Model。 很多代碼跟前面類似,這里只列出核心代碼,ViewModel層的

public interface BaseViewModel {void onDestroy(); }public abstract class AbstractViewModel<T extends ViewDataBinding> implements BaseViewModel {public T mViewDataBinding;public AbstractViewModel(T viewDataBinding){this.mViewDataBinding=viewDataBinding;}@Overridepublic void onDestroy() {mViewDataBinding.unbind();} }public class SampleViewModel extends AbstractViewModel<ActivitySampleMvvmBinding> {public SampleViewModel(ActivitySampleMvvmBinding viewDataBinding) {super(viewDataBinding);}public void getUserInfo(String uid, Callback1<SampleModel.UserInfo> callback){//從網絡或緩存獲取信息SampleModel.UserInfo userInfo=new SampleModel.UserInfo();userInfo.setName("tom");userInfo.setAge(18);callback.onCallBack(userInfo);} } 復制代碼

ViewMode層主要處理業務邏輯和獲取數據,mViewDataBinding是通過View層傳遞過來。

private SampleViewModel mSampleViewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivitySampleMvvmBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sample_mvvm);mSampleViewModel=new SampleViewModel(binding);setDataToView();}private void setDataToView(){mSampleViewModel.getUserInfo("uid", new Callback1<SampleModel.UserInfo>() {@Overridepublic void onCallBack(SampleModel.UserInfo userInfo) {mSampleViewModel.mViewDataBinding.setUser(userInfo);}});} 復制代碼

xml layout代碼在上面介紹databing的用法時已給出,通過上面代碼我們就將數據UserInfo跟View進行綁定了。比如我們更新用戶信息,可以直接對View上的屬性進行修改: mSampleViewModel.mViewDataBinding.tvName.setText(“rose”); 也可以通過修改UserInfo實體類的字段信息: mSampleViewModel.mViewDataBinding.setUser(userInfo);

從此告別MVP中View層好多接口的問題,讓View變得更簡潔,修改任何一方,兩者都會保持數據同步。

5、MVVM 總結

看起來MVVM很好的解決了MVC和MVP的不足,但是由于數據和視圖的雙向綁定,導致出現問題時不太好定位來源,有可能數據問題導致,也有可能業務邏輯中對視圖屬性的修改導致。如果項目中打算用MVVM的話可以考慮使用官方的架構組件ViewModel、LiveData、DataBinding去實現MVVM

關于MVC,MVP,MVVM如何選擇的探討

前面在介紹MVC、MVP、MVVM時并沒有去詳細列出他們的優缺點,主要原因有兩個:

  • 網上這方面總結的還是挺多的
  • 其實關于架構,設計,模塊化等等,它們的優缺點沒有絕對的,主要看實現者如何去做
  • 比如在mvp中我們要實現根據業務邏輯和頁面邏輯做很多Present和View的具體實現,如果這些case太多,會導致代碼的可讀性變差。但是通過引入contract契約類,會讓業務邏輯變得清晰許多。因此不管是用哪種設計模式,只要運用得當,都可以達到想要的結果。

    如果非要說怎么選的話,以我淺薄的知識建議如下:

  • 如果項目簡單,沒什么復雜性,未來改動也不大的話,那就不要用設計模式或者架構方法,只需要將每個模塊封裝好,方便調用即可,不要為了使用設計模式或架構方法而使用。
  • 對于偏向展示型的app,絕大多數業務邏輯都在后端,app主要功能就是展示數據,交互等,建議使用mvvm。
  • 對于工具類或者需要寫很多業務邏輯app,使用mvp或者mvvm都可。
  • 如果想通過一個項目去學習架構和設計模式,建議用MVC然后在此基礎上慢慢挖掘改進。最后你可能發現,改進的最終結果可能就變成了mvp,mvvm。
  • PS:代碼部分很多只是為了演示具體設計模式原理,部分為偽代碼,還有些代碼寫的不是那么嚴謹。望勿怪

    轉載于:https://juejin.im/post/5c6bd1bde51d45141d1d8d8d

    總結

    以上是生活随笔為你收集整理的MVC、MVP、MVVM,我到底该怎么选?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。