MVP那些事兒 (2) 初探MVC架構

目錄

MVP那些事兒(1)……用場景說話ios

MVP那些事兒(2)……MVC架構初探算法

MVP那些事兒(3)……在Android中使用MVC(上)設計模式

MVP那些事兒(4)……在Android中使用MVC(下)緩存

MVP那些事兒(5)……中介者模式與MVP的關係服務器

MVP那些事兒(6)……MVC變身爲MVP網絡

MVP那些事兒(7)……Repository設計分析架構

爲何要先介紹MVC?

若是你要想更佳深入的理解MVP,並在實際開發中靈活的應用,那麼就要先了解它的低配版MVC,他倆只是一步之遙,先了解MVC再學習MVP,MVP的優點才能凸顯出來,這樣連貫性的學習纔會加深對MVP的理解。框架

咱們在上一章提到,MVP那些事兒(2) 用場景說話 對咱們的案例進行MVC的設計,也就是第一步,如何實現一個MVC,在實現以前咱們先搞清楚幾點概念。異步

MVC的做用?它是設計模式嗎?是框架嗎?是架構嗎?

MVC屬於分層架構中的一員,不管是哪個層從複用性和擴展性都是由當前業務所限制的,若是一開始就從複用和擴展上做爲出發點來使用MVC的話,必定要有足夠的開發經驗(並非不能夠,分層架構也是能夠有擴展性的,但要考慮主次),除非你很是明確將來軟件的複雜度。舉個例子,好比有一個算法,它處理一組數據所需的時間關係以下:10條,須要1秒,20條須要1.8秒,30條須要2.5秒,,,,100條須要6秒,這個時間複雜度能夠看出什麼,能夠看出這個算法處理的數據量越大,它的處理所消耗的時間遞增越緩慢,也就越是大數據量越能體現它的價值,再舉一個實際中的例子,人均100的餐廳,兩我的去也許每一個人只能嚐到2~3種菜樣,但四我的去,每一個人會嚐到4~6菜樣,20我的去,你也許能夠把他們家的菜嚐個遍,MVC也是如此,軟件的複雜度越高,越能體現MVC的擴展價值,這就是我爲何要講不要一上來就想從擴展性做爲使用MVC的出發點,除非你是一個頗有經驗的人,能提早估計出項目的一個大體的複雜度。更穩妥的方式應該是在項目的推動中不斷的優化本身的架構,不少萌新會進入到誤區,一看MVP你們都在用,本身設計一個吧,到最後發現根本就你一我的在吃菜,更關鍵的是別人想和你吃也吃不了,不通用,根本沒法體現它的擴展價值,負責人發現後第一反應是,你搞這麼多接口抽象類幹什麼?就你一我的用,搞事情。 佈局

MVC不是簡單的設計模式

一個只爲了分層就能夠被叫作設計模式的話,那麼外觀模式看來還不是最尷尬的模式,因此它不能簡單的稱呼爲設計模式,由於它的範圍和深度更加立體,稱爲架構更爲穩當,固然也能夠稱之爲複合設計模式,它裏面包含了,策略,組合,觀察者,等設計模式。那麼,架構和框架的關係又是什麼呢?

架構和框架說的不是一回事兒

MVC是一種架構思想,而基於這個思想的框架也叫MVC框架,在ios的開發中,系統爲咱們實現了公共的視圖類UIView,和控制器類UIViewController,還有大名鼎鼎的Struts2框架,都是基於MVC架構設計出來的框架(基於MVVM架構的DataBinding,Architecture Components框架),框架是一個有邊界的可擴展集,它在可擴展的同時也是有邊界的,也就是說你只能在這個框架裏玩耍,而沒法超出這個框框。若是你只是在項目中使用了MVC的思想去作分層,那麼這個項目或模塊用的就是MVC架構設計,若是你用了Struts框架,那麼這個項目使用了MVC框架。當你向別人介紹你的項目時,你能夠這麼說:個人項目使用的是MVVM架構,具體用到了Architecture Components做爲框架來進行開發,千萬不要說成:你們好,我來介紹一款基於MVVM框架設計的Architecture Components架構,這聽的得多彆扭啊。

一句話總結——架構是藍圖,而框架是實實在在的產品,MVP架構就一個,而基於MVP架構設計的框架能夠是千千萬萬個。

以上就是對MVC的一個大體的介紹,學習MVC以前,要先會寫,學會了寫,再學習用,接下來咱們先實現一個MVC框架。

實現MVC什麼?MVC(框架)

在第一章的場景裏咱們挑一個需求,咱們來實現一個向服務端請求數據,並顯示在列表的需求。

需求時序圖
在Android中咱們實現上面的需求,一般狀況是在界面的Create時,調用一個請求接口,經過異步的方式返回數據,待數據返回時更新UI,咱們用一個Activity來實現:

public class TasksActivity extends AppCompatActivity {
    protected void onCreate(Bundle savedInstanceState) {
        //...初始化
        //請求列表數據
        Data data = loadData();
    }
    void onDataCallBack (Data data) {
        //更新列表
        upDateList(data);
    }
}
複製代碼

這是一段簡單的示例代碼,一般狀況下咱們用像loadData這樣的方法去請求數據,而且綁定監聽,監聽數據的返回,當數據返回時,像onDataCallBack這樣的回調方法會被觸發,同時進行ui的更新。

一樣的需求,用MVC寫一遍

MVC分別爲Model,View,Controller,顧名思義,首先咱們須要建立這三個對象,第二步,咱們把這三個對象組合起來,咱們先一個一個的認識它們,逐個擊破,首先從簡單的來,Model,

什麼是Model,它的職責

邏輯層(領域層)Domain Object,邏輯執行體,除此以外也能夠兼顧JavaBean的職責,但Model層可不是簡單的Value Object。而 JavaBean也就是Value Object,只是用來封裝數據,不具有Model層的職責,固然也能夠把JavaBean看成Model類的一個內部類來使用,固然也能夠單獨一個類,一般咱們也會這麼做,方便複用。 萌新⚠️

一、JavaBean不是Model,但Model也能夠包含JavaBean的職責,但不是必須的。 二、Model是用來處理數據的,如獲取數據(本地或者服務端),數據處理,如CURD。

按照上面的定義咱們來寫一個Model

/**我是一個Model**/
public class TasksRepository {
    //從服務器請求獲取數據
    void getTasks() {}
    //從內存緩存獲取數據
    Data getTaskCache() {}
    //從磁盤緩存獲取數據
    Data getTaskDiskCache(){}
    //保存一條數據
    boolean saveTask(Task task) {}
    //對數據進行排序
    Data orderData(Data data, int orderType){}
}
複製代碼

首先咱們建立一個Model類名爲TasksRepository,首先不要關內心面的Data和Task對象,它們只是普通的Bean對象,TasksRepository裏面包含了五個方法,按照以前的定義,它是有獲取數據的職責的,因此這其中三個方法都是和獲取數據相關,好比getTasks,你能夠調用網絡組件進行數據的獲取,它還能夠對數據進行CURD的操做,好比savaTask的方法用來保存一條數據,還能夠對數據進行業務處理,好比用orderData方法對數據進行從新的排序。

一句話總結,Model負責獲取數據,操做數據,和對數據進行業務處理。

什麼是View,它的職責

接下來咱們講一講View,View就是咱們的視圖層。

一、它的主要職責爲呈現Model的數據、主動詢問狀態或被動的監聽 二、通知控制器Controller去處理一些事情 三、接收Controller,編輯本身與Model無關的狀態

按照View的職責咱們來設計一下這個類

/**我是一個View**/
public class TaskView {
    //當列表初始化後,告訴控制器該加載數據了
    void viewCreate() {
        controller.loadNomData();
    }
    //更新列表
    void upDateList() {
        //主動請求Model獲取數據
        Data data = tasksRepository.getTaskCache();
        //更新ui
        list.update(data);
    }
    
    void beginLoadData(){
        list.showHead();
    }
}
複製代碼

在TaskView中也就是咱們的視圖對象,它包含了倆個對象,分別爲controller和taskeRepository,controller就是控制器對象,咱們下一個講它,taskeRepository就是咱們的模型,上面提到過它,先不要關心這兩個對象是怎麼初始化來的,要關心的是View視圖對象是包含了C和M的,按照職責它必須這麼作,首先像viewCreate這類方法通常是在界面初始化時調用的(在Android 中多是Activity或者Fragment初始化時調用的,也多是某一個執行動做),讓controller去執行loadNomData的方法請求數據,這裏惟一須要注意的是,並無明確的告訴controller請求的數據是從什麼地方來的,也許是緩存,也許是網絡請求,view是無需關心這一點的。同時還要注意的是,在講解Model的時候已經明確了Model是有獲取數據的職責,可是在上面的示例中,**爲何是controller去負責獲取數據,而不是用Model?也就是咱們的tasksRepository對象?**請你們記住這個疑問,會在講解Controller時回答。

第二個方法upDataList方法,

//更新列表
void upDateList() {
    //主動請求Model獲取數據
    Data data = tasksRepository.getTaskCache();
   //更新ui
    list.update(data);
}
複製代碼

它的內部是經過tasksRepository對象的getTaskCache()方法獲取數據,這個方法在Model的定義裏面,你們還有印象吧。講到這裏,**你們可能發現有一個嚴重的漏洞,view在執行tasksRepository.getTaskCache()時,是怎麼知道這個數據已經準備好了呢?**看view的職責1:

主動的問詢或者監聽Model

咱們把調用tasksRepository.getTaskCache()看做爲主動的問詢,而在主動問詢前,View應該獲得一個有效的通知,這個通知應該由Model發起,當監聽到Model:個人數據準備好了,你來拿吧時,View會去主動的向Model獲取數據。舉個現實中的例子,你在網上買東西,如今通常都往快遞櫃裏投放,等到短信通知你快遞到了時,你纔會去快遞櫃裏拿商品,但也許你實在等不及了,也能夠每天打電話,咱們就不詳細討論了,View和Model但關係也就是觀察者與被觀察者的關係。但是,在上面的示例中咱們沒有寫出監聽Model的代碼,請你們記住這個疑問,我會在後面講解三者的依賴綁定時會揭曉答案。 最後一個方法,beginLoadData(),

void beginLoadData(){
        list.showHead();
}
複製代碼

當開始請求數據時,list會顯示本身的頭佈局,像beginLoadData這樣編輯view自己的方法在實際開發過程當中還有不少,它們關注的是控件自己的狀態,最重要的,這樣的方法可能會被Controller隨時的調用,咱們在講解Controller時進行講解。

什麼是Controller,它的職責

Controller,也就是咱們的控制器,它把視圖的操做發送到模型。

接收View的操做,並轉調給Model 改變View的狀態

按照上面的職責,咱們嘗試的設計一下這個類:

/**我是一個Contorller**/
public class TasksController {
    
    void loadNomData() {
        if(tasksRepository.getTaskCache() == null){
            //執行Modle
            tasksRepository.getTasks();
            //執行View
            view.beginLoadData();
        }
    }
}
複製代碼

在對Controller講解以前,咱們先停頓一下,在以前的介紹中咱們好像遺留了幾個問題,在介紹View時,我用加租文字的方式標示了三個問題,在介紹Controller時咱們將要解決掉問題1,和問題3。咱們一塊兒回顧一下這2個問題:

疑問1,在講解Model的時候已經明確了Model是有獲取數據的職責,可是在上面的示例中,爲何是controller.loadNomData()去負責獲取數據,而不是用Model?也就是咱們的tasksRepository對象?

這個問題要從Contrller的職責提及:接收view的操做,並轉調給Modle。什麼是view的操做,好比list的下拉刷新操做,轉調給Model,也就是說其實Controller並無實際的實現加載數據的代碼,而是讓Model去執行,解釋完之後,看一下TasksController裏的第一個方法loadNomData(),

void loadNomData() {
        if(tasksRepository.getTaskCache() == null){
            //執行Modle
            tasksRepository.getTasks();
            //執行View
            view.beginLoadData();
        }
    }
複製代碼

它內部第一條語句:

tasksRepository.getTasks();
複製代碼

而tasksRepositor對象就是咱們的Model,它執行了getTasks()的操做,其實controller的loadNomData()方法只是對這個過程進行了一個封裝。聽完上面的解釋,咱們知道Controller是這麼設計的,但是又一個問題出現了,雖然咱們知道了Controller轉調了Model的方法,但是我爲何要這麼作?我直接在View裏調用tasksRepository.getTasks();不能夠嗎? 清你們記住這個問題,我下一章爲你們解答,咱們先學會寫,再去研究怎麼用。

疑問2,像beginLoadData這樣編輯View自己狀態的方法在實際開發過程當中還有不少,它們純粹關注的是控件自己的狀態,最重要的,這樣的方法可能會被Controller隨時的調用。

咱們先回顧一下這個方法beginLoadData()

//controller會隨時調用
void beginLoadData(){
        //顯示列表的頭部,改變了列表的屬性
        list.showHead();
}
複製代碼

咱們仍是從Controller的職責來講,Controller有權利對View的狀態進行改變,無論是通知的形式,仍是直接的訪問。並且View的職責裏也說明了,它是能夠接收Controller更改本身的狀態,而更關鍵的一點這個狀態的改變是無需依賴Model的,更加的純粹。

有了上面問題的承上啓下,咱們再回頭看一下TasksController裏的loadNomData()方法,它首先判斷了是否能夠從tasksRepository裏拿到緩存,若是沒有就執行getTasks(),同時通知view我要開始加載數據了,view會在beginLoadData()方法中對本身的列表控件進行一個顯示頭部的處理,至關規範的一個封裝。

**總結:**到此,咱們已經學習完了MVC這三個層的定義和職責。在文章的開頭我有講過,要想用MVP,就要先用MVC,要想用MVC就要先會"寫"MVC,寫纔是第一步,咱們首先把MVC這三個層,拆分紅三個片斷,每個片斷都規範好它們的職責,而後咱們再想辦法把它在組裝在一塊兒,在下一章咱們要解決如下問題:

一、如何把這三個片斷組裝起來?在Android裏怎麼寫? 二、view在執行tasksRepository.getTaskCache()時,是怎麼知道tasksRepository數據已經準備好了呢?怎麼通知view的?

MVP那些事兒(3)……在Android中使用MVC(上)

謝謝你們關注和評論,更新的有些慢,不如關注我一下,隨時知道更新進度。

相關文章
相關標籤/搜索