2017/4/24

使用 MVP 時在設計上的考量

在「FluxJava: 給 Java 使用的 Flux 函式庫」這篇文章中提到,設計中使用 MVP 最大的問題,是會讓不同的畫面形成一組、一組的 Class,但各組之間是獨立的。MVP 最基本的設計概念中,只描述了同一組內 Class 如何互動,並沒有提到組內的 Class 如何跨組與其他的 Class 互動。當設計上出現要跨組的情況時,就得要仰賴設計者的功力與經驗了。

就 MVP 的精神,View 要負責的工作,只是把 Presenter 送來的 Model 內容呈現在畫面上。並且,與使用者互動,接收使用者的意圖、收集使用者輸入的資料,再交由 Presenter 處理。至於其他與 Business Logic 有關的事,不會由 View 來經手。

畫面的切換由誰負責

在只有單一畫面的情況之下,看起來很合理、分工明確,在設計上應該是個無可挑剔的方案。只是當畫面一多起來,隨之出現了一個問題:畫面的切換由誰負責?

有問題嗎?View 是負責使用者互動的,當然畫面的轉換由 View 來做囉!

也對,以 Android 平台為例,發送 Intent 大多是在 Activity 或是 Fragment 上處理的,再自然不過了。等新的 View 被載入後,再去啟動與其配對的 Presenter、讓 Presenter 把資料送過來。流程上都還在設計的預想之內,跨組的工作的確就由 View 來完成即可。

在畫面與畫面的順序固定的情況下,看起來是沒什麼問題。如果畫面的切換要依據資料的狀態來決定呢?

剛才有提到,為了保持每個 Class 任務的單純性,View 應該與 Business Logic 無關。要讓 View 根據資料狀態來決定,某種程度上就是 Business Logic,這樣是不是違反了一開始提到的精神?

而且判斷時所依據的資料,很可能跟 View 要顯示的內容無關,又或者是一個複雜的邏輯,又更加深了是否該放在 View 上的疑慮。

Presenter 是否要跨平台

不放在 View 又要放在哪?Presenter 上嗎?

這應該是在簡單的 MVP 結構之下,大多數人的選擇。當整個結構中,就只有 Model、View、Presenter,自然是只能由 Presenter 來存取資料庫、負責資料處理邏輯。此時再多加一項,依據資料決定畫面切換方式,好像也沒有什麼不恰當。

先回到 Android 平台上,來看看這樣的安排會出現什麼情況。

Presenter 要能夠控制 Activity 的轉換,必須要取得 Context,這也意味著 Presenter 與 Android 平台綁在一起。所以當這樣的設計內容,要移到不同的平台上,Presenter 就有可能要面臨大幅度在設計上的修改。換句話說就是,把工作放在 Presenter 上,會將設計限制在特定的平台上。

把 Context 排除在 Presenter 之外,就可以避免這個問題了嗎?

就算是 Presenter 不直接控制 Activity 的轉換,只決定要切換哪一個 Activity,Presenter 勢必要有 Activity 的資訊,不管是 Type 或是 Class 名稱。換了一個平台,顯示畫面的 Class 還會是相同的名稱嗎?可以確定的是 Type 一定不一樣。

MVP 套用在 Android 上的問題

那就不要跨平台,大不了新的平台把設計再重做一次!

其實對 Android 平台來說,問題還不止如此。以 Master-Detail 的畫面配置當例子,不同螢幕尺寸的情況下,會有一個 Activity 和二個 Activity 的差別。

原本在大螢幕中,一個 View、一個 Presenter 就做完的事,到了小螢幕卻變成二個 View,那 Presenter 也要跟著拆成二個?

假設答案是肯定的,也就是說同一個 App 裡,同樣用途的畫面就做了三組 View/Presenter。不對,在 Android 的 Master-Detail 的範本中,Master 的 Activity 是共用的,那豈不變成同一個 View 有二個 Presenter 配對?

這樣的設計好像有點累贅,但真的要在這樣的設計下,把流程串起來也不是不行。不過,要由 Master-Detail 跳到其他畫面的工作,應該三個 Presenter 都相同,是不是要抽離出來,不要在 Presenter 裡做?

結果,畫面切換要由誰負責的問題又繞回到原點。

當有使用 Service 或 BroadcastReceiver 的需求時,又會引發不同的問題。

沒有套用 MVP 之前,都是很直覺地在 Activity 中進行 Service 的使用。Service 大部份是用來進行後端資料處理的作業,這樣的 Service 該由 View 來啟動嗎?不是應該透過 Presenter?

現在前端不適合啟動 Service,那該由誰接手?Presenter 嗎?

是比 View 合適的選擇,但這樣又會回到 Presenter 要不要獨立於平台之外的問題上。

再者,Service 完成作業之後,如果要以 BroadcastReceiver 的流程來通知外部。BroadcastReceiver 可以放在 Activity 上嗎?MVP 傳送資料不是都要透過 Presenter?Service 在用來處理資料時,算是後端,不用經過 Presenter 嗎?

MVP 設計的下一步

在「MVC 與 MVP 的抉擇」一文中提到,把 MVP 中的 View 視為 Sub System,其實並不是突發奇想。而是在導入 MVP 時,用來應對在設計上所碰到的諸多問題的一個環節。

如果要深入的說明整個構思的內容,由於篇幅可能會很大,未來在時間允許之下,會有更多有關這方面的文章來做討論。