MVP那些事兒(6)MVC轉化爲MVP

目錄

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

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

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

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

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

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

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

立刻就要過春節了,如今還在單位刷掘金的同窗,可見大家在領導的心目中是何其重要,在這裏,首先祝你們新春快樂、萬事如意,新年新氣象,來年再創新高!post

新年尬聊

快速回顧

前面花了大量的篇幅去介紹分層架構的相關知識點,以及MVC架構是如何實現的,上一篇介紹了中介者模式與MVP間的關係,這期間應用了大量的場景描述,好比租房子的故事,項目開發的故事,加班的故事,這些鋪墊都是爲了能講明白MVP,更是爲了在之後的實戰中能更加自由的去擴展和設計出新的變種,在項目中熟練應用,這就須要知其然,知其因此然。this

這一篇的能容比較單一,如何去設計一個MVP,由於有以前的鋪墊,咱們直接用MVC的例子進行改寫。spa

首先回顧一下MVC和MVP的區別,看下面這兩張設計圖,通過以前反覆屢次的總結和概括,得出一個結論:

在MVC中,C的職責很是的單一,就是負責處理流程控制的,而在MVP中除了負責流程控制外,它還要負責M與V之間的一個隔離的做用,是做爲一箇中介者存在的。

什麼是中介者? MVP那些事兒(5)中介者與MVP 歡迎回顧。

中介者的職責,隔離

那麼MVP的本質上就是中介者,從上面的結論中不難看出,只要讓Controller賦予了中介者的職能,那麼它就會變爲Presenter。

隔離就意味着,在設計的過程當中,M和V之間是不能相互引用的,那麼全部的交互都須要經過Controller去完成的,只要知足了這點,Controller就會升級爲Presenter。咱們把以前的MVC調用方式的代碼搬出來,從應用層倒推設計:

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);
    }
}
複製代碼

這一段代碼是前幾章中示例MVC中用到的,能夠看到,在初始化TaskRepository時,經過構造函數將view注入到了TaskRepository,而這裏的TaskRepository就是Model層的實例。咱們講過,在MVP中,M與V不能以任何形式見面,可見上面的寫法在MVP中是不容許的,因此須要從新設計,不容許View以各類形式出如今Moodel中,這其中就包括依賴注入的三種方式。其次,因爲MainActivity是View的具體實現,很顯然它實現了TaskView,雖然TaskView在設計中並無刻意的去包含Model,但卻沒法控制其子類包含有Model,這裏TaskRepository在MainActivity中實例化了,它們一個表明着M,一個表明着V,可是在這裏,其實並不會對總體設計帶來影響,畢竟子類的行爲是不受控制的,但爲了規範使用,通常狀況下Model的初始化是放在Presenter的實例中。在我看來這其實仍是有點好處,Presenter會去處理Model的初始化,這樣,當View想使用不一樣的Model時,直接去使用不一樣Presenter便可。通過簡單的分析,代碼這樣去修改

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);
    }
}

/** 因爲TasksController中
public class TasksController implements Observer{
    
    public TasksController(TasksView view) {
        //經過構造函數接收view
        this.view = view;
        //經過構造函數初始化Model
        TasksRepository model = new TasksRepository();
        //Controller -> Model
        model.addObserver(observer: this);
    }
   .
   .
   .
}
複製代碼

經過以上的改造,Controller就變成了Presenter,別忘記修改類名,在真實的項目中,各個層大可能是以接口的形式定義的,這一點都不奇怪,沒有接口哪裏來的設計,因此別忘了作接口設計,在層的設計中,都是經過具體業務反推而來的,憑空想象是不可取的,若是有必定的積累和經驗,能夠先設計出來幾個通用接口,而後再慢慢完善,好比Model加載數據的功能是比不可少的,那麼能夠先定義出loadData,比View接收到Presenter的通知,處理視圖的方法,再好比Prensenter統一處理髮起獲取數據的請求等等。而這些具體業務的接口,纔是MVP框架豐滿的關鍵,但前提是咱們必定要去遵循MVP架構的原則去設計,那麼接下來,咱們嘗試這去設計這些接口。

設計接口,讓MVP框架變的更增強壯

框架即爲骨骼,而接口和它的實現則是肌肉系統,接口決定了肌肉的走向,而實現則決定了肌肉的能力。

場景

在最近的工做中,有這麼一個需求,就是須要在App中同時存在http的請求和tcp的請求: 因爲我不知道我獲取的具體是什麼東西,因此起名爲getObject,同時我也不清楚具體參數和返回值(先忽略太多具體的業務)。

讓咱們一塊兒從頭擼一個MVP框架

一、定義Model

public interface DataSource {
    void getObject();
}
複製代碼

二、定義Presenter

public interface Presenter {
    void loadSometing();
}
複製代碼

三、定義View

public interface View {
    void setPresenter(Presenter p);
}
複製代碼

四、定義Presenter與Model間的監聽

public interface PresenterListener {
    void onSametingCallBack()
}
複製代碼

首先實現Model

一、http請求的Model

public class RemoteHttpRepository implements DataSource {
    @override
    void getObject() {
        //執行http請求
    }
}
複製代碼

二、tcp請求的Model

public class RemoteTcpRepository implements DataSource {
    @override
    void getObject() {
        //執行tcp請求
        ..
        if(listener != null) {
            listener.onSametingCallBack();
        }
    }
    
    void addListener(PresenterListener listener) {
        
    }
}
複製代碼

實現View

public abstruct class BaseView implements View {
    Presenter presenter;
    void setPresenter(BasePresenter presenter) {
        this.presenter = presenter
    }
    
    abstruct onViewDoSamething();
}
複製代碼

實現 Presenter

public class BasePresenter implements Presenter ,PresenterListener{
    RemoteTcpRepository repository;
    View view;
    public BasePresenter (View view) {
        this.view = view;
        //這裏使用TCP請求
        repository = new RemoteTcpRepository();
        repository.addListener(presenterListener: this);
    }
    @Override
    void loadSomething() {
        repository.getObject();
    }
    
    @Override
    void onSametingCallBack() {
        view.onViewDoSamething();
    }
}
複製代碼

固然別忘了加入監聽,上面的BasePresenter實現了監聽,咱們在以前的章節介紹詳細的介紹過監聽的部分。

How To Use

public class MainActivity extends AppCompatActivity implments BaseView{
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Presenter presenter = new BasePresenter(view: this);
            presenter.loadSamething();
        }
        
        @Override
        void onViewDoSamething() {
            //do view 
        }
    }
複製代碼

接口的定義要根據具體的業務去具體定義,上面的例子就是很是具體的業務去決定了接口的定義,因此,千萬不要照葫蘆畫瓢,關鍵是要理解思想。

總結

到此爲止整個MVP的「肌肉」雛形就出來了,咱們繼續向裏面添加內容:好比,添加泛型對象、實現具體的網絡請求功能、是否支持數據緩存、以及Presenter的生命週期控制,這些都須要你們根據實際需求去填充了,後天就是除夕了,立刻就要過節了,好開心,你們都好好多陪陪家人吧,工做什麼的都去見鬼吧,哈哈哈,咱們節後再繼續。

相關文章
相關標籤/搜索