MVP那些事兒(3)……在Android中使用MVC(上)架構
MVP那些事兒(4)……在Android中使用MVC(下)框架
立刻就要過春節了,如今還在單位刷掘金的同窗,可見大家在領導的心目中是何其重要,在這裏,首先祝你們新春快樂、萬事如意,新年新氣象,來年再創新高!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架構的原則去設計,那麼接下來,咱們嘗試這去設計這些接口。
框架即爲骨骼,而接口和它的實現則是肌肉系統,接口決定了肌肉的走向,而實現則決定了肌肉的能力。
在最近的工做中,有這麼一個需求,就是須要在App中同時存在http的請求和tcp的請求: 因爲我不知道我獲取的具體是什麼東西,因此起名爲getObject,同時我也不清楚具體參數和返回值(先忽略太多具體的業務)。
public interface DataSource {
void getObject();
}
複製代碼
public interface Presenter {
void loadSometing();
}
複製代碼
public interface View {
void setPresenter(Presenter p);
}
複製代碼
public interface PresenterListener {
void onSametingCallBack()
}
複製代碼
首先實現Model
public class RemoteHttpRepository implements DataSource {
@override
void getObject() {
//執行http請求
}
}
複製代碼
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實現了監聽,咱們在以前的章節介紹詳細的介紹過監聽的部分。
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的生命週期控制,這些都須要你們根據實際需求去填充了,後天就是除夕了,立刻就要過節了,好開心,你們都好好多陪陪家人吧,工做什麼的都去見鬼吧,哈哈哈,咱們節後再繼續。