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

爲何要先介紹MVC?

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

目錄

MVP那些事兒(1)……用場景說話服務器

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

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

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

MVP那些事兒(5)……中介者模式與MVP的關係函數

MVP那些事兒(6)……MVC變身爲MVP工具

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

快速回顧

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

在上一篇中,咱們學習了MVC架構圖原理和它的進化過程,並經過is a,has a,依賴注入原則對MVC中三個對象進行組合,同時從無到有的搭建出MVC框架的基本雛形,ui

靈與骨,血與肉

在上一篇中,咱們的MVC框架已經完成了初步的搭建,固然,還不是框架最終形態,雖然三個對象經過某種聯繫組合了起來,但讓框架真正運轉起來還須要最關鍵的一個機制,那就是溝通機制,就比如人類,光有骨架和血肉還不能稱之爲一個完整的「人」,你還須要神經系統幫助你去看,聽,和感覺。

溝通機制

在Java的面向對象設計中,監聽是一種經常使用的溝通機制,在觀察者模式裏,一個監聽機制所涉及到的對象包括:監聽者(Observer)、被監聽者(Obserable);涉及到的環節包括:訂閱(Subscribe)、發送事件、及處理事件。

場景

使用如下兩個需求做爲本章場景:

一、列表展現

二、列表支持下拉刷新,上拉加載更多

實現監聽機制

既然監聽是一個經常使用的溝通手段,咱們就開始「升級」咱們的框架

監聽的好處

在開始以前,依舊要用一個場景來描述一下監聽的好處,還記得以前租房子的故事嗎?在這個故事裏,我故意忽略了溝通的機制,就是爲了留在這一章節講的,當租客聯繫到中介時,這是一個主動的動做,租客是發起方,當和中介創建聯繫後,他們雙方互留電話,同時中介找到合適的房東,而且也留下了聯繫方式,這個時候中介開始等待房東的迴應,這期間中介什麼都幹不了,一分鐘一個電話的詢問房東是否考慮好了,那麼中介的下場只有兩個,房東很生氣,一分鐘一個電話,你沒事兒,我還有事兒呢,你等我消息不行嗎?直接拉黑。或者因爲中介一次只能處理一個事情,這件事處理不完,就不能處理下一件事,效率低下被公司開除。租客也是同樣,一次次的去詢問中介,找到房子了嗎?等待他的下場也有兩個,1、一次次的電話,致使電話費報表,2、因爲電話費太貴,打算一天問一次,因爲獲取消息不及時,結果房子被別人租走了,也就是消息的即時性低,而露宿街頭(雖朱門酒肉臭,但別路有凍死骨,願在外漂泊的大家在這寒冷的冬天裏有一個溫暖的所在)。

爲了不上面的悲劇發生,中介公司改善了溝通機制,首先從租戶的角度,經過主動向租客彙報進度來解決消息即時性的問題,讓租戶第一時間獲得最新狀況,其次,中介再也不催促房東,而是讓房東考慮好後通知中介,當中介收到房東的消息後第一時間通知給租戶,經過這兩個環節的改造,一條高效的通知鏈就造成了。

爲MVC框架增長監聽

Modle的職責是對數據的生產和處理,並在結束一些耗時的操做後,應該主動的通知給Controller,因此Model爲被觀察對象,而Controller爲觀察對象,它觀察着Model的一舉一動,爲了能更好的觀察Model的行爲,Controller派了一個「眼線」到Model中,這個「眼線」的職責就是監聽Model的一舉一動。

第一步,定義一個「眼線」

/**我是一個「眼線」
public interface Observer {}
複製代碼

這裏的眼線就是一個觀察對象的接口,但具體讓它作什麼,咱們還不清楚,經過接口的形式將來會有很好的擴展性,定義完眼線,如何使用呢?

還記得上一篇中View是被怎麼使用的嗎?它被Actvity實現了,也便是說咱們這裏的「眼線」也應該被某個對象去實現,不然它將沒有任何用處,因爲是Controller派出了一個「眼線」,因此應該由Controller去使用,使用的兩種途徑,要麼本身具有「眼線」的功能,也就是is a,要麼就是本身招募一個「眼線」,Has a。

一、我就是眼線,眼線就是我

/**我是一個Contorller,同時我就是個眼線**/
public class TasksController implements Observer{
    void loadNomData() {}
}
複製代碼

TasksController,經過實現Observer接口,具有了觀察者的能力。

二、我招了個眼線

/**我是一個Contorller**/
public class TasksController{
    //我招募了一名眼線
    private Observer observer = new Observer() {};
    void loadNomData() {}
}
複製代碼

TasksController,經過內部實例化了一個Observer接口,間接的得到了觀察者的能力。

以上兩種均可以得到觀察者的能力,可是從擴展性來說,仍是儘可能去選擇第一種方式。

第二步,放置眼線

有了眼線後,咱們還要將它放置在被觀察者的內部,這纔算完成了觀察者與被觀察者之間的訂閱。

public class MainActivity 
extends AppCompatActivity 
implments TasksView{
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,經過構造器注入
        TasksController controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.setController(controller);
    }
}
複製代碼

這是上一篇內容中的代碼段,將來都會圍繞着這段代碼進行改進,看最下面這一行:

model.setController(controller);
複製代碼

其實,這一步就是model持有了controller,因爲咱們如今的controller具有了觀察者的職責,同時在咱們真正的使用中沒有必要把整個controller的職責都暴露給model,而model也只須要controller觀察者的能力,好讓它即時的把結果告知controller,因此咱們能夠這樣改造一下這段代碼爲:

model.addObserver(observer: controller);
複製代碼

看起來傳的參數依舊是controller,只不過改了一個方法名,這沒什麼區別啊,我想說的是區別仍是有的,方法名的改變意味着這段代碼的業務變了,雖然都是controller,沒改以前是所有的controller,而下面的代碼是告訴你們,我只使用controller觀察者的部分,其餘的我不關心,雖然你全給了我,但用那些是個人事情。

改造事後的Activity:

public class MainActivity
extends AppCompatActivity
implments TasksView{
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,經過構造器注入
        TasksController controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.addObserver(observer: controller);
    }
}
複製代碼

第三步,發送事件

這個時候,Model已經獲取到了觀察者,也就是Controller,那麼當Model本身發生變化時,就能夠即時的通知給Controller了,咱們試着發一個事件,可是在發送事件前,不要忘了眼線尚未具體的能力,咱們只是定義了一個接口,眼線具體有什麼能力仍是要結合具體業務去定義,這不屬於架構的部分,更偏向於業務層,這裏咱們就模擬當Model獲取到數據後,通知Controller,我拿到數據了,因此讓眼線有通知數據ok的功能:

/**我是一個「眼線」
public interface Observer {
    //數據OK
    void onDataComplate(Data data);
}
複製代碼

目前眼線已經準備完畢,就等着Model來使用了,咱們用Model來發送一個事件

Model :TasksRepository

/**我是一個Model**/
    public class TasksRepository {
        //眼線集中營
        public static ArrayList<Observer> observers = 
            new ArrayList<Observer>();
        viod addObserver(Observer observer){
            observers.add(observer);
        }
        //從服務器請求獲取數據
        void getTasks() {
            //訪問服務器,耗時。。。服務器返回時,
            Data data = fromServer();
            //發送事件
            for(Observer observer : observers){
                observer.onDataComplate(data);
            }
        }
        //從內存緩存獲取數據
        Data getTaskCache() {}
        //從磁盤緩存獲取數據
        Data getTaskDiskCache(){}
        //保存一條數據
        boolean saveTask(Task task) {}
        //對數據進行排序
        Data orderData(Data data, int orderType){}
    }
複製代碼

在實際的開發中,Model可不是隻爲了某一個Controller去監聽的,它能夠被任何想要監聽它的人監聽,你只要送一個眼線過來,當Modle有變更時,Model會通知全部關心它的人,因此Model裏面有一個Observer的集合:

public ArrayList<Observer> observers = 
            new ArrayList<Observer>();
複製代碼

當Model發生了變化,就會遍歷這個集合去通知全部的觀察者,而眼線在這裏派上了用場

for(Observer observer : observers){
    observer.onDataComplate(data);
}
複製代碼

第四步,接收事件

處理事件的特性是觀察者的本質,Controller既然是觀察者,那麼處理事件應該由本身去完成:

Controller :TasksController

/**我是一個Contorller**/
public class TasksController implements Observer{
    //接收事件
    void onDataComplate(Data data) {
        //處理事件
    }
    void loadNomData() {}
}
複製代碼

TasksController實現了Observer的onDataComplate方法,當Model發送事件後,onDataComplate方法便能接收到,咱們就能夠在這裏處理事件了,到此爲止整個事件從建立處處理就完成了,這也就是觀察者模式的核心,若是之後須要本身實現一個觀察者模式,那麼就按照上面四個步驟來寫,絕對不會懵圈並且思路會異常的清晰。

那麼View呢?

上面的場景提到過,當房東考慮好後通知給中介,中介會第一時間通知租客結果,那麼具體改如何作呢?

public class MainActivity
extends AppCompatActivity
implments TasksView{
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,經過構造器注入
        TasksController controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.addObserver(observer: controller);
    }
}
複製代碼

回過頭來看Acivity的代碼中的這一段:

//初始化Controller,this就是View,經過構造器注入
TasksController controller = 
            new TasksController(tasksView:this);
複製代碼

首先,經過構造函數,讓controller持有view,當controller接收到model的通知時,緊接着通知view,因此TasksController的代碼還需改進:

/**我是一個Contorller**/
public class TasksController implements Observer{
    //經過構造函數接收view
    public TasksController(TasksView view) {
        this.view = view;
    }
    //接收事件
    void onDataComplate(Data data) {
        //處理事件,緊接着向view發送事件
        view.onDataBack(data);
    }
    void loadNomData() {}
}
複製代碼

咱們看處理事件的部分,直接執行了view的方法,也就是所謂的即刻通知。

讓View也接口化

按早以前Controller觀察者化的思路,咱們能不能讓view也變成觀察者,固然能夠並且是必須的,讓view 去觀察Controller的變化,Controller又去觀察Model的變化,那麼整個鏈式反應就完成了。具體步驟就不分析了,上一個完整的代碼:

View :TasksView

/**我是一個View,我自己就是個眼線**/
    public interface TaskView {
        void onDataBack(Data);
        //當列表初始化後,告訴控制器該加載數據了
        void viewCreate();
        //更新列表
        void upDateList();
        //just for ui
        void beginLoadData();
    }
複製代碼

Activity:

public class MainActivity
extends AppCompatActivity
implments TasksView{
    private TasksController controller;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,經過構造器注入
        controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.addObserver(observer: controller);
        viewCreate();
    }
    //接收controller的事件,並處理
    void onDataBack(Data){
        //處理事件。。。
    }
    //當列表初始化後,告訴控制器該加載數據了
    void viewCreate(){
        controller.loadNomData();
    }
    //更新列表
    void upDateList(){}
    //just for ui
    void beginLoadData(){}
}
複製代碼

總結:

這一篇中,咱們經過觀察者模式對咱們的框架進行了改進,經過監聽,讓MVC的三個對象造成了一個事件傳送帶,事件就比如有了方向通常從Model出發,通過Controller最終流向View,然後期咱們能夠在這條鏈路上對咱們的事件作任何想要作的操做,而最終的接收者View是徹底不用關心的,亦或者view能夠自定義本身想要的數據,在Model尚未發送事件前。說的更確切點,咱們能夠在事件的發送前,傳輸中,接收前,這三個點作不少咱們但願作的事情,好比數據在接收前的一些排序的轉變,這些咱們都會以接口的 方式暴露出來。到此,MVC的介紹結束,但框架的搭建尚未完成,在接下來的被容裏,咱們經過MVP的方式對框架進行進一步的改進,同時加入一些實質些的工具,讓框架具有一些基本的業務功能。

相關文章
相關標籤/搜索