前端的MVC和MVP和MVVM
- MVC(Model-View-Controller)
- MVP(Model-View-Presenter)
- MVVM(Model-View-ViewModel)
- M-V- X 本質都是一樣的 重點還是在於M-V 的橋樑要靠 X來牽線。
- 所以無論是複雜化 簡單化 還是修改流程,基本都是因為技術棧變化了 對應做的調整。
-
X的模式之間不同 主要是 M與V 的資料傳遞的流程不同。
資料傳遞的流程不同來源於執行環境技術棧能夠做到的事情不同。
- 在相同技術棧下 能夠實現的各種 X都可以是大同小異的。
- 在不同技術棧下 相同的X可能實現都大相徑庭,僅有非常抽象的流程類似。
Model-View-Controller
在ASP還在奮鬥的時候WebForm突然到來,正如WebForm還在奮鬥的時候MVC突然到來。當然,我這裡講的MVC還是最原始的MVC,因為MVC在我們還在爭論的時候已經發展了許多不同分支了。
有一點相信大家同意的就是,我們今天討論爭論的MVC、MVP、MVVM、Code Behind等等都源自於職能分化和規劃的思想與目的,MVC不是它們的開始,但是一個很好的開始。
相信MVC的模型大家很熟悉,也很容易找到,我們這裡用一下某百科的圖:
我們可以看到的是,介面被分到了View,資料分到了載體Model上由Model“攜帶”,業務集中在Controller中,而推動業務的事件由使用者與View互動,通過View向Controller發動。
當然,實現由很多種,每種細節上都有不同,所以我才只講也只能講大致的MVC。MVC的其中一個缺點便是沒有明確的定義,所以不同的實現(比如Struts和ASP.NET MVC)細節上都是不一樣的。
我們需要知道的是,MVC並不是像上面所說的一些事情那樣是一種“必然的”結果,它是一系列必然結果問題中的一種解決方案,而且是不完美的解決方案。我們順著推理去到一個地方很容易犯的一個錯誤就是認為路只有這一條而忽視其他可能性(估計這也是導致很多爭鬥的原因)。另外,我們在討論一件事物不完美的時候是有一個情境的,所以請不要像“我說它色彩單一,然後你把它塗成彩色後證明我是錯的”。
MVC的一般流程是這樣的:View(介面)觸發事件--》Controller(業務)處理了業務,然後觸發了資料更新--》不知道誰更新了Model的資料--》Model(帶著資料)回到了View--》View更新資料
這裡也不多再陳述MVC的原理、實踐等等,因為這就太長篇大論了。
Model-View-Presenter和一些衍生
像我們之前推理的,分化是一種需求的必然結果,但卻沒有個一個確定的結果,比如Code Behind和Code Block的問題等等。
MVC順著需求把UI相關的工作分化成了三份,這點經過實踐證明無可厚非。但是它們的三角關係卻被一些人認為帶來了一些問題,或者應該說他們有“更好的”解決方案。
在只有Code Behind和Code Block的那個時候維護是很直接的,不是在同一段程式碼內解決就是在同一個關聯的事件上解決。三角關係的問題就是維護問題。在MVC,當你有變化的時候你需要同時維護三個物件和三個互動,這顯然讓事情複雜化了。
我們之前說到,隨著摩爾定律,軟體的需求不斷地變化和變得龐大。隨著需求變得龐大的時候,需求變化也變得頻繁,這是一個出現了無數次以後也將會出現無數的無數次的一個問題,所以它需要一個解決方案,哪怕它不一定能被解決。
為了解決需求變化,從《人月神話》到敏捷到DDD,它不是我們已經解決了的問題,而是我們正在解決的問題。放在UI的模式和MVC上來講,就是優化或者替代MVC模式,其中之一就是Model-View-Presenter(MVP)模式。
我們先看看兩個MVP模式的圖:
(圖一)
(圖二)
兩幅圖是不同的,但是對MVC的改進的思想卻是一樣的:切斷的View和Model的聯絡,讓View只和Presenter(原Controller)互動,減少在需求變化中需要維護的物件的數量。
這種方式很符合我們的期待,因為我們傾向於:
- 用更低的成本解決問題
- 用更容易理解的方式解決問題
許多時候並不是一種模式不好,而是因為人沒辦法執行,比如不容易理解,我們就會選擇容易理解的方式。計算機依賴摩爾定律用數量的增長來解決問題,而人是用方式的改變來解決問題的。同樣因為客觀原因我們不善於維護多個物件和多個物件之間的關係,所以我們改變了,或者說簡化了這種方式。
MVP定義了Presenter和View之間的介面,讓一些可以根據已有的介面協議去各自分別獨立開發,以此去解決介面需求變化頻繁的問題。上面兩圖都有介面,不過介面的實現和使用細節不一樣,不過思想上是一致的。
在這裡要提到的是,事實上,需求變化最頻繁的並不一定是最接近使用者的介面,但基本可以確定的是,最接近使用者的介面是因為需求變化而需要最頻繁更改的。當然,如果View如果是API而不是UI,那就另說了。
還有一些用來“解決”MVC這項缺點的比如有:ASP.NET MVC的ViewBag,Cocoa的delegate。它們都為了簡化資料更新的問題而存在,包括MVVM。
Model-View-ViewModel
先直接看看Model-View-ViewModel(MVVM)的圖:
從圖上看是比MVP簡單了,更不用說MVC了。個人不認為MVVM是從MVP進化而來,我只覺得這是在MVP之後出現的一種“更好的”UI模式解決方案,但是用MVP來與之對比比較容易說明問題。
ViewModel大致上就是MVP的Presenter和MVC的Controller了,而View和ViewModel間沒有了MVP的介面介面,而是直接互動,用資料“繫結”的形式讓資料更新的事件不需要開發人員手動去編寫特殊用例,而是自動地雙向同步。資料繫結你可以認為是Observer模式或者是Publish/Subscribe模式,原理都是為了用一種統一的集中的方式實現頻繁需要被實現的資料更新問題。
比起MVP,MVVM不僅簡化了業務與介面的依賴關係,還優化了資料頻繁更新的解決方案,甚至可以說提供了一種有效的解決模式。
至此,我們能理解為什麼許多人認為MVVM是最好的一種模式,沒有之一。但事實上,MVVM也是依賴於我們至今所講的“特有的情境”。
當然,最優雅的也是第一個能作代表的實踐就是Windows Presentation Foundation(WPF)了。
Web
之上,我們在模式演變的推論基本上都還是基於桌面軟體的,但是過去十年卻是網際網路的時代。實際上大部分讓大家爭議的並不是在桌面領域最合適的是那個,而是在Web領域的模式問題,也就是在B/S場景下的問題。
當軟體離開單機,去到網路的時候,因為場景變了,所以原有的解決方案也變了,不過需求依然是不變的。我們依然要解決的問題是使用者互動與資料更新的問題,還有維護等等的問題。
當場景變到Web的時候,我們發現MVVM用來做服務端是極其不適用的,至少現在是不適用的。而MVP你提都不用提。為什麼呢?因為:
- 網路資源成本過高
- 開發成本過高
問大家一個問題,當一個網頁的資料更新後,你希望更新使用者看到的資料,你會怎麼做?
一般情況下,你會:
window.location.reload();
就算你不這麼做,使用者也會:
F5
就像之前說的,我們會選擇更直接的方式解決問題。直接重新整理頁面的原因是因為這樣更直接,更容易解決資料更新的問題。
很多時候你不會願意為了一個數據更新寫一個AJAX,更別說這個AJAX要帶來Loading、事件順序處理、網路問題、異常處理等等,這就是開發成本過高。
另一個網路成本過高就更容易解釋了,雖然寬頻是基本包月的,但也不帶這麼用的,何況還有移動使用者。更主要的原因是,在本地軟體,更新資料是一個引用問題,而在網路應用上,這是一個傳輸問題。傳輸成本遠高於引用成本,引用之上頂多是在本地記憶體中再進行一次記憶體拷貝。
這個時候,我們會更傾向於用MVC模式,因為在Web層面,我們更傾向於一次性更新資料。
Web的MVVM
所有問題都不是問題,就算有問題也要解決問題。
為什麼這個標題下突然冒出這麼一句話?我想說的是,需求依舊是不變的,是推動進步的原動力。
還有我之前說過,當我們討論或者爭論一個問題的時候,問題的物件已經發生改變了,而且這次是在我們討論這個問題之前已經發生改變了。
網路資源成本不斷下降,相信已經不需要多提及。摩爾定律和相近的一些原理正在發揮著它應用的作用,網路頻寬越來越高、相應速度越來越快。
如果傳輸因為相對成本下降而導致資料傳輸的成本低於開發人員拒絕客戶的成本,那麼它就會被實現而不是被拒絕。
另外還有一點就是因為技術的進步,技術的資源不斷被更大規模地壓榨,需求也不斷地增長,那麼需求始終會增長超過相對不變的開發成本的。比如jQuery的出現解決了很多問題,我們現在更多地去使用AJAX,哪怕很大一部分依然是為了解決網路資源不足的問題;我們會用更多的樣式程式碼而用了相對更少的圖片;我們不再那麼依賴Flash一類的向量圖解決方案而直接錄製視訊。
至少上一節我們說到的兩個導致大家選用MVC的問題都正在被解決,所以我們有理由相信未來Web不僅僅需要MVC,可能會需要MVVM或其他解決方案。至少我們能理解容易理解為什麼前端會出現一些MVVM的框架,比如先驅knockout.js和AngularJs。這些框架本身的好壞就不作討論了,因為我們討論的是模式。
在Web上,MVVM的對比物件就不是MVC,而是Code Block。
資料即時更新的需求在擴大,但未必有達到一定要用MVVM這一等級的高大上的模式,實際上如果你要更新一個數據,你還是會採取:
$('.notice').html('傳送成功!');
因為......我們依然會採取更直接的方式解決問題......
實際上,現在Web MVVM主要並不是用在了Web或者Wap上,而是移動App上。按照前面的說法,只可能是:
- HTML+JS比原生在一些場景上更適合Native
- 在移動App上比Web上更適合使用MVVM
哪怕是Native開發,實際上iOS的開發上也是用類似的資料繫結的方式的。這裡也不深究了,畢竟我也不算懂iOS。
要說的是,在Web MVVM或者Web的模式上,也就是Web的富應用上,現在還不過是個初期由膨脹的需求推動的階段。重要的不是技術會怎麼走,而是需求和客觀條件會怎麼走。
可能Webform會因為高速開發而煥發第二春,它的AJAX的模式也十分滿足於簡單開發,但似乎大家需要的不是GUI式的網頁。
結尾語
我們不一定需要MVVM,但我們一定需要更強大的方式去解決不斷膨脹的Web需求。
我們可以預見的是:
- 會有更強大的瀏覽器
- 會有更強大的JavaScript或者框架
- 會有更加適合的模式
除去客氣話的部分,我還是想說,在不同的需求下其實有最適合的解決方案,通常讓我們糾結的不是因為哪個解決方案更好,而是我們看到的條件不夠多。
編譯語言當然比解釋語言效率高,但考慮到開發和維護成本,JavaScript等始終會大行其道,比如Node.JS、Python;.NET和微軟當然很強大,移植.NET到其他平臺也很容易,但微軟是家有自己商業模式和要賺錢的公司;當然有些實踐和技術更好,但其他開發人員會避開甚至否定自己不擅長的東西,大家都喜歡確定的東西;有些技術更強大,但是隻是基於特殊的客觀條件和需求,如果你想做大,要麼創造客觀條件,要麼把它結合需求......