MVC绅这、MVP、MVVM架構(gòu)分析與比較

一在辆、MVC(Model-View-Controller)

  • 模型層(Model)
    負(fù)責(zé)存儲(chǔ)证薇、檢索、操縱來自數(shù)據(jù)庫或者網(wǎng)絡(luò)的數(shù)據(jù)
  • 視圖層(View)
    用戶界面匆篓,一般采用XML文件進(jìn)行界面的描述
  • 控制層(Controller)
    業(yè)務(wù)邏輯處理


    image.png

1. 工作原理

  1. 當(dāng)用戶出發(fā)事件的時(shí)候浑度,view層會(huì)發(fā)送指令到controller層,自己不執(zhí)行業(yè)務(wù)邏輯鸦概。
  2. Controller執(zhí)行業(yè)務(wù)邏輯并且操作Model箩张,但不會(huì)直接操作View,可以說它是對(duì)View無知的窗市。
  3. model層更新完數(shù)據(jù)然后對(duì)視圖進(jìn)行更新先慷,用戶得到反饋。

2. MVC代碼實(shí)例

  • 1.先實(shí)現(xiàn)一個(gè) model咨察,需要有通知View更新的能力,當(dāng)model加載成功论熙,模擬從網(wǎng)絡(luò)或者本地獲取數(shù)據(jù),需要告知View更新:
public class MvcModel {
    String mId;
    MvcActivity mActivity;

    public MvcModel (MvcActivity activity) {
        this.mActivity = activity;
    }
    public void loadModel (){
        //模擬從網(wǎng)絡(luò)或者本地獲取數(shù)據(jù)
        mId = "20170923";
        mActivity.updateUI(this);
    }
}
  • 2.View
    View需要發(fā)出點(diǎn)擊事件摄狱,并且傳遞Controller,同時(shí)需要根據(jù)Model更新UI:
public class MvcActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       //省略
        final MvcController controller = new MvcController(this);
        mFindBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                controller.loadData();
            }
        });
    }

    public void updateUI (MvcModel model) {
        mID.setText(model.mId);
    }
}
    1. Controller :有時(shí)候我們的Activity既充當(dāng)View也充當(dāng)Controller脓诡, 這里為了更好的理解MVC无午,將Activity進(jìn)行了拆解。
public class MvcController {
    MvcActivity mActivity;
    MvcModel mModel;

    MvcController (MvcActivity activity) {
        this.mActivity = activity;
    }

    public void loadData (){
        mModel = new MvcModel(mActivity);
        mModel.loadModel();
    }
}

3. MVC調(diào)用鏈

  1. View:OnClick ->
  2. Controller:loadData->
  3. Model:loadModel->
  4. View:updateUI

4. MVC優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):
    把業(yè)務(wù)邏輯全部分離到Controller中祝谚,模塊化程度高宪迟。當(dāng)業(yè)務(wù)邏輯變更的時(shí)候,不需要變更View和Model踊跟,只需要Controller換成另外一個(gè)Controller就行了踩验。
  • 缺點(diǎn):
    1、 Controller測(cè)試?yán)щy商玫。因?yàn)橐晥D同步操作是由View自己執(zhí)行箕憾,而View只能在有UI的環(huán)境下運(yùn)行。在沒有UI環(huán)境下對(duì)Controller進(jìn)行單元測(cè)試的時(shí)候拳昌,Controller業(yè)務(wù)邏輯的正確性是無法驗(yàn)證的:Controller更新Model的時(shí)候袭异,無法對(duì)View的更新操作進(jìn)行斷言。
    2炬藤、 xml作為view層御铃,控制能力實(shí)在太弱,Activity基本上都是View和Controller的合體沈矿,既要負(fù)責(zé)視圖的顯示又要加入控制邏輯上真,承擔(dān)的功能很多,導(dǎo)致代碼量很大羹膳。如想去動(dòng)態(tài)的改變一個(gè)頁面的背景睡互,或者動(dòng)態(tài)的隱藏/顯示一個(gè)按鈕,這些都沒辦法在xml中做陵像,只能把代碼寫在activity中就珠,造成了activity既是controller層。
    3醒颖、 view層和model層之間存在耦合妻怎。

二、MVP(Model-View-Presenter)

  • 模型層(Model)
    負(fù)責(zé)存儲(chǔ)泞歉、檢索逼侦、操縱來自數(shù)據(jù)庫或者網(wǎng)絡(luò)的數(shù)據(jù)。
  • 視圖層(View)
    用戶界面腰耙,一般采用XML文件進(jìn)行界面的描述偿洁。
  • 邏輯處理層(Presenter)
    作為View與Model交互的中間紐帶,處理與用戶交互的負(fù)責(zé)邏輯沟优。
image.png

1. 工作原理

  1. View 接受用戶請(qǐng)求
  2. View 傳遞請(qǐng)求給Presenter
  3. Presenter做邏輯處理,修改Model
  4. Model 通知Presenter數(shù)據(jù)變化
  5. Presenter 更新View

2. MVP代碼實(shí)例

    1. MVP中Model睬辐、View挠阁、Presenter中的聯(lián)系件
public interface MvpContract {
    interface View {
        void updateUI();
    }

    interface Model {
        void loadModel();
    }

    interface Presenter {
        void loadData ();
    }
}
    1. 還在MVC的例子上變動(dòng)宾肺,需要先對(duì)Model進(jìn)行封裝,當(dāng)loadModel后侵俗,不直接通知View更新锨用,而是通知Presenter。
public class MvpModel implements MvpContract.Model{
    String mId;
    OnGetListener mListener;

    public MvpModel (OnGetListener listener) {
        this.mListener = listener;
    }
   @Override
    public void loadModel (){
        //模擬從網(wǎng)絡(luò)或者本地獲取數(shù)據(jù)
        mId = "20170923";
        if (mListener != null) {
            mListener.onSuccess(this);
        }
    }
    interface OnGetListener {
        void onSuccess (MvpModel model);
    }
}
    1. View需要發(fā)出點(diǎn)擊事件隘谣,并且傳遞給Presenter 增拥,最后也由Presenter去通知View更新UI:
public class MvpActivity extends AppCompatActivity implements MvpContract.View {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       //省略
        final MvpPresenter presenter = new MvpPresenter(this);
        mFindBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                presenter.loadData();
            }
        });
    }
    @Override
    public void updateUI (MvpModel model) {
        mID.setText(model.mId);
    }
}
    1. Presenter ,接收到來自View的操作命令后寻歧,進(jìn)行邏輯處理掌栅,處理Model,修改完成后 通知View進(jìn)行修改码泛。
public class MvpPresenter implements MvpContract.Presenter  {
    MvpContract.View  mView;
    MvpContract.Model mModel;

    MvpPresenter (MvpContract.View view) {
        this.mView= view;
    }
    @Override
    public void loadData (){
        mModel = new MvpModel(new MvpModel.OnGetListener() {
            @Override
            public void onSuccess(MvpModel model) {
                mView.updateUI(model);
            }
        });
        mModel.loadModel ();
    }
}

3. MVP調(diào)用鏈

  1. View:OnClick ->
  2. Presenter:loadData->
  3. Model:loadModel->
  4. Presenter:onSuccess->
  5. View:updateUI

4. MVP優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):
    1猾封、便于測(cè)試。Presenter對(duì)View是通過接口進(jìn)行噪珊,在對(duì)Presenter進(jìn)行不依賴UI環(huán)境的單元測(cè)試的時(shí)候晌缘。可以通過Mock一個(gè)View對(duì)象痢站,這個(gè)對(duì)象只需要實(shí)現(xiàn)了View的接口即可磷箕。然后依賴注入到Presenter中,單元測(cè)試的時(shí)候就可以完整的測(cè)試Presenter業(yè)務(wù)邏輯的正確性阵难。
    2岳枷、避免了傳統(tǒng)開發(fā)模式中View和Model耦合的情況,提高了代碼可擴(kuò)展性多望、組件復(fù)用能力嫩舟、團(tuán)隊(duì)協(xié)作的效率。
  • 缺點(diǎn):
    1怀偷、 View(Activity)需要持有Presenter的引用家厌,同時(shí),Presenter也需要持有View(Activity)的引用椎工,增加了控制的復(fù)雜度饭于;
    2、MVC中Activity的代碼很臃腫维蒙,轉(zhuǎn)移到MVP的Presenter中掰吕,同樣造成了Presenter在業(yè)務(wù)邏輯復(fù)雜時(shí)的代碼臃腫。

三颅痊、MVVM(Model-View-ViewModel)

  • 模型層(Model)
    負(fù)責(zé)存儲(chǔ)殖熟、檢索、操縱來自數(shù)據(jù)庫或者網(wǎng)絡(luò)的數(shù)據(jù)
  • 視圖層(View)
    用戶界面斑响,一般采用XML文件進(jìn)行界面的描述
  • 視圖-模型層(ViewModel)
    負(fù)責(zé)View和Model之間的通信菱属,以此分離視圖和數(shù)據(jù)钳榨。


    image.png

1. 工作原理

  1. View 接收用戶交互請(qǐng)求
  2. View 將請(qǐng)求轉(zhuǎn)交給ViewModel
  3. ViewModel 操作Model數(shù)據(jù)更新
  4. Model 更新完數(shù)據(jù),通知ViewModel數(shù)據(jù)發(fā)生變化
  5. ViewModel 更新View數(shù)據(jù)

2. MVVM代碼實(shí)例

  • 1.Model
public class MvvmModel {
    String mId;
    OnGetListener mListener;

    public MvvmModel (OnGetListener listener) {
        this.mListener = listener;
    }
    public void loadModel (){
        //模擬從網(wǎng)絡(luò)或者本地獲取數(shù)據(jù)
        mId = "20170923";
        if (mListener != null) {
            mListener.onSuccess(this);
        }
    }
    interface OnGetListener {
        void onSuccess (MvvmModel model);
    }
}
  • 2.ViewModel
public class MvvmViewModel extends BaseObservable{
    public ObservableField<String> mId = new ObservableField<>();
    public MvvmViewModel() {

    }
   public void doGetId(View view){
        loadData();
    }
    public void loadData() {
        MvvmModel model = new MvvmModel(new MvvmModel.OnGetListener() {
            @Override
            public void onSuccess(MvvmModel model) {
                mId.set(model.mId);
            }
        });
        model.loadModel();
    }
}
  • 3.接著使用databinding語法 對(duì) xml 進(jìn)行數(shù)據(jù)綁定,我們將 Click事件纽门、輸出結(jié)果都綁定到ViewModel上薛耻。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable name="viewModel" type="com.liujc.mvvm.MvvmViewModel"/>
    </data>
    <LinearLayout   
        <TextView
                android:id="@+id/id"
                android:layout_width="match_parent"
                android:layout_height="20dp"
                android:text="@{viewModel.mId}"/>
          <Button
                android:id="@+id/findBtn"
                android:onClick="@{viewModel.doGetId}"
                android:text="獲取Id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
    </LinearLayout>
</layout>
  • 4.最后在View(Activity)中引入ViewModel :
public class MvvmActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ActivityMvvmBinding binding =       DataBindingUtil.setContentView(this,R.layout.activity_mvvm);

        final MvvmViewModel viewModel = new MvvmViewModel();
        binding.setViewModel(viewModel);
    }

}

3.MVVM優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):
    1、低耦合赏陵。View可以獨(dú)立于Model變化和修改饼齿,一個(gè)ViewModel可以綁定到不同的”View”上,當(dāng)View變化的時(shí)候Model可以不變蝙搔,當(dāng)Model變化的時(shí)候View也可以不變缕溉。
    2、可重用性杂瘸。你可以把一些視圖邏輯放在一個(gè)ViewModel里面倒淫,讓很多view重用這段視圖邏輯。
    3败玉、獨(dú)立開發(fā)敌土。開發(fā)人員可以專注于業(yè)務(wù)邏輯和數(shù)據(jù)的開發(fā)(ViewModel),設(shè)計(jì)人員可以專注于頁面設(shè)計(jì)运翼,生成xml代碼返干。
    4、ViewModel解決MVP中View(Activity)和Presenter相互持有對(duì)方應(yīng)用的問題血淌,界面由數(shù)據(jù)進(jìn)行驅(qū)動(dòng)矩欠,響應(yīng)界面操作無需由View(Activity)傳遞,數(shù)據(jù)的變化也無需Presenter調(diào)用View(Activity)實(shí)現(xiàn)悠夯,使得數(shù)據(jù)傳遞的過程更加簡(jiǎn)潔癌淮,高效。
  • 缺點(diǎn):
    1沦补、ViewModel中存在對(duì)Model的依賴乳蓄。
    2、數(shù)據(jù)綁定使得 Bug 很難被調(diào)試夕膀。你看到界面異常了虚倒,有可能是你 View 的代碼有 Bug,也可能是 Model 的代碼有問題产舞。
    3魂奥、IDE不夠完善(修改ViewModel的名稱對(duì)應(yīng)的xml文件中不會(huì)自動(dòng)修改等)。

四易猫、DataBinding

DataBinding是2015年谷歌 I/O大會(huì)上介紹了一個(gè)數(shù)據(jù)綁定框架耻煤,以前我們可能需要在每個(gè)Activity里寫很多的findViewById,不僅麻煩,還增加了代碼的耦合性违霞,如果我們使用DataBinding嘴办,就可以拋棄那么多的findViewById,省時(shí)省力买鸽。
雙向綁定的概念讓傳統(tǒng)的布局文件由被動(dòng)轉(zhuǎn)為主動(dòng),數(shù)據(jù)驅(qū)動(dòng)UI贯被,而且View與ViewModel實(shí)現(xiàn)了完美的解耦眼五,這也解決了MVP模式下的缺點(diǎn)。

五彤灶、小結(jié)

  • 從MVC看幼、MVP到MVVM,實(shí)際上是模型和視圖的分離過程幌陕。MVC中模型和視圖沒有完全分離诵姜,造成Activity代碼臃腫,MVP中通過Presenter來進(jìn)行中轉(zhuǎn)搏熄,模型和視圖徹底分離棚唆,但由于V和P互相引用,代碼不夠優(yōu)雅心例。ViewModel通過Data Binding實(shí)現(xiàn)了視圖和數(shù)據(jù)的綁定宵凌,解決了這種MVP的缺陷。
  • 可參考一套Android App基礎(chǔ)框架
    架構(gòu)設(shè)計(jì):從MVC止后、MVP到MVVM
    網(wǎng)絡(luò)訪問:支持REST瞎惫、HTTPS及SPDY的Retrofit+Okhttp
    響應(yīng)式編程:RxJava/RxAndroid解決方案
    依賴注入:Dagger2和ButterKnife使用
  • 框架的選擇
    任何的項(xiàng)目框架,都是為項(xiàng)目服務(wù)的译株。沒有絕對(duì)的好壞之分瓜喇,只有更合適的選擇。在項(xiàng)目進(jìn)展的不同階段歉糜,做出最合適的調(diào)整乘寒,才是是更適合團(tuán)隊(duì)項(xiàng)目發(fā)展的框架。謹(jǐn)記任何的項(xiàng)目設(shè)計(jì)现恼,都是要圍繞項(xiàng)目發(fā)展階段肃续,團(tuán)隊(duì)成員規(guī)模,和團(tuán)隊(duì)整體能力而定的叉袍。切莫為了設(shè)計(jì)而設(shè)計(jì)始锚,為了框架而框架≡洌快速瞧捌,高效的配合整個(gè)團(tuán)隊(duì)進(jìn)展項(xiàng)目,才是最合適的架構(gòu)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姐呐,一起剝皮案震驚了整個(gè)濱河市殿怜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌曙砂,老刑警劉巖头谜,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鸠澈,居然都是意外死亡柱告,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門笑陈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來际度,“玉大人,你說我怎么就攤上這事涵妥」粤猓” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵蓬网,是天一觀的道長(zhǎng)窒所。 經(jīng)常有香客問我,道長(zhǎng)拳缠,這世上最難降的妖魔是什么墩新? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮窟坐,結(jié)果婚禮上海渊,老公的妹妹穿的比我還像新娘。我一直安慰自己哲鸳,他們只是感情好臣疑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著徙菠,像睡著了一般讯沈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婿奔,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天缺狠,我揣著相機(jī)與錄音,去河邊找鬼萍摊。 笑死挤茄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冰木。 我是一名探鬼主播穷劈,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼笼恰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了歇终?” 一聲冷哼從身側(cè)響起社证,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎评凝,沒想到半個(gè)月后追葡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奕短,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年辽俗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篡诽。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖榴捡,靈堂內(nèi)的尸體忽然破棺而出杈女,到底是詐尸還是另有隱情,我是刑警寧澤吊圾,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布达椰,位于F島的核電站,受9級(jí)特大地震影響项乒,放射性物質(zhì)發(fā)生泄漏啰劲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一檀何、第九天 我趴在偏房一處隱蔽的房頂上張望蝇裤。 院中可真熱鬧,春花似錦频鉴、人聲如沸栓辜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藕甩。三九已至,卻和暖如春周荐,著一層夾襖步出監(jiān)牢的瞬間狭莱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工概作, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留腋妙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓仆嗦,卻偏偏與公主長(zhǎng)得像辉阶,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容