MVC->MVP->MVVM架構完整演變過程剖析


在之前對於MVP這種架構風格已經進行了深入的學習了,接下來則打算學習一下MVVM這種架構,MVC、MVP、MVVM這三者基本上會被人一起問到的,而對於MVVM,google官方推出了一個dataBinding的MVVM的框架,而從學習的角度直接上框架並非是一個非常好的學習方式,所以這次就手把手的一步步通過一個小案例來實現MVVM框架,對其原理有一個本質的了解,這樣在下一次學習dataBinding時也能做到心中有數。

MVC:

思想:

架構理解:

對於上圖的理解,簡單描述整個過程就是用戶觸發了View的一個事件,然后則會轉到Controller中進行處理,而它又會去操作Model,最終Model處理完了會更新到UI上來。這里用一個偽代碼來模擬一下這個過程:

而其實有些MVC會是這樣的一個關系:

具體實現:

接下來則回到Android的代碼上來,先來簡單搭個框架:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/et_data1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/et_data2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_save"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="save" />

</LinearLayout>

沒啥好解釋的,默認Android的這個代碼框架就屬於MVC風格的,這個都耳熟能詳了,這里還是啰嗦一下:對於V來說就是我們的布局文件,而M則是DateCenter這個類,而C則是MainActivity。那為啥會出現MVP、MVVM這種新的框架出來呢?因為目前MVC框架中的Activity太重了,跟M和V都進行耦合在一塊了,所以MVP出現了。

MVP:

思想:

架構理解:

其中可以看到跟MVC中最大的區別在於MVP的Model和View之間沒有引用了,然后之前的Controller變成了Presenter了。

具體實現:

接下來咱們來將它改造成MVP,首先先來新建一個P:

然后它會操作Model,所以這里將這個代碼牽移到P中:

此時Activity調整為:

此時一個基本的MVP就出現了,其中“View跟Controller給拆開了,並提取出了一個Presenter”,目前這個基本的MVP框架中P是直接持有了具體Activity的引用,然后目的是用來調用它里面的刷新界面的方法:

 

很明顯對於P來說不需要用到MainActivity中的所有信息,只需要知道這個界面是如何更新UI的就行了,所以直接持有Activity的引用設計不是太合理,面向接口編程是最提倡的,也就是能只獲取最小的信息則就獲取最小的,這樣會解耦,所以咱們將其抽象成一個接口,里面會存放各個跟UI相關的操作接口:

思考:在上面中加粗了一句話“View跟Controller給拆開了,並提取出了一個Presenter”,那能否不提一個Presenter,而達到同樣的效果呢?其實是可以的,而這種寫法在實際工作中也是很頻繁的,下面改裝一下,這里先將建幾個包將其分開一下:

而這里則對MvcActivity傳統的寫法進行調整一下:

怎么能讓控件層與View之間耦合不那么緊呢?其實就是想辦法把這段代碼給去掉:

其實就是將這個設置封裝到View里面既可:

package com.android.mvc_mvp_mvvm_demo.mvc;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

import com.android.mvc_mvp_mvvm_demo.R;

public class DataView extends LinearLayout {

    private EditText et_data1;
    private EditText et_data2;

    public DataView(Context context) {
        super(context);
    }

    public DataView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public DataView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void showData(String[] data) {
        et_data1.setText(data[0]);
        et_data2.setText(data[1]);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        et_data1 = findViewById(R.id.et_data1);
        et_data2 = findViewById(R.id.et_data2);
    }
}

為啥要改上面這種比較簡單的代碼呢?其實這里是要來對於很多人都說的:“MVP要比MVC要好,MVC的View和Controller都混到一塊”這樣的觀點持懷疑態度,很明顯通過上面的這樣改良,也沒有提取出一個P,跟MVP的效果差不多呀, 那為啥要說MVP比MVC要好呢?可能有些人會說MVP不是會提取出一個View的接口嘛,那對於上面改良的這種代碼也可以提取呀,下面試一下:

所以其實對於MVC和MVP框架本質來說其實是一樣的,當然細節會有不同,這種觀點其實沒必要較真,只是為了了解其了本質才這樣挖掘的,而平常在討論這倆框架的區別時,還是可以說:“Android自帶的框架就是MVC,而抽出來一個P層的則是MVP”。

MVVM:

接下來則來看最后一種架構了,這種目前還木有在真實項目中用過,但是對於它的了解也早就有所耳聞,相比MVP而言,它的數據如果發生變化了會立馬反饋到UI上,而不需要通過回調通知UI進行刷新,反過來如果UI更新了數據狀態也會自動到去將Model中的數據給自動更新 。

思想:

具體實現:

先來新建一個ViewModel:

此時Activity就可以這樣來調用了:

 

接下來要實現數據自動顯示在界面上該如何修改呢?怎么明顯Activity跟ViewModel需要進行綁定才行,所以新建一個類:

在這里面則需要監聽textView和text的變化,對於TextView的變化監聽有現成的API這個不用操心,但是對於第二個參數text很顯然不能,所以此時我們得將ViewModel中的這塊得封裝一下才行:

具體修改如下:

此時回到ViewBinder類中:

哦,原來雙向綁定的核心是這么搞的,就是哪方改變了再通知另一方,好接下來咱們再回到ViewModel中:

 接下來則可以進行Activity與ViewModel的綁定了,先來在ViewModel定義一個綁定接口供Activity來調用:

好,接下來調用一下:

至此一個簡單的MVVM框架就搭建完了,說實話還是有些麻煩的,不過好在Google針對MVVM推出了成熟的框架,如開篇有說,DataBinding,商用的話基本上會基於這個框架來進行MVVM的開發,這次對於MVVM的核心原理了解了之后,下一次就准備來學習一下DataBinding框架的使用及原理啦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM