【編者按】近日,阿里無(wú)線(xiàn)事業(yè)部前端工程師寒泉在一篇文章《談?wù)刄I架構設計的演化》中表示,從經(jīng)典MVC到MVVM,UI架構經(jīng)過(guò)數次重大變遷。今天無(wú)數經(jīng)過(guò)演繹的MVC實(shí)現和科普文,要么是原本作者概念已經(jīng)很混亂,摻雜私貨,要么為了適配現代的標記語(yǔ)言和控件模式,自己修改了經(jīng)典MVC中的一些概念和耦合關(guān)系。實(shí)際上今天MVC已經(jīng)沒(méi)法作為一種交流的標準詞匯了。該文從MVC的發(fā)展歷程著(zhù)手,對其概念及演進(jìn)過(guò)程進(jìn)行了肅清,以防開(kāi)發(fā)者被誤導。下面為原文。
經(jīng)典MVC
在1979年,經(jīng)典MVC模式被提出。
在當時(shí),人們一直試圖將純粹描述思維中的對象與跟計算機環(huán)境打交道的代碼隔離開(kāi)來(lái),而Trygve Reenskaug在跟一些人的討論中,逐漸剝離出一系列的概念,最初是Thing、Model、View、Editor。后來(lái)經(jīng)過(guò)討論定為Model、View和Controller。作者自言“最難搞的就是給這些架構組件起名字”。
因為當時(shí)的軟件環(huán)境跟現在有很大不同,所以經(jīng)典MVC中的概念很難被現在的工程師理解。比如經(jīng)典MVC中說(shuō):“View永遠不應該知道用戶(hù)輸入,比如鼠標操作和按鍵?!睂σ粋€(gè)現代的軟件工程師來(lái)說(shuō),這聽(tīng)上去相當不可思議:難道監聽(tīng)事件不需要類(lèi)似這樣的代碼嗎?
view.onclick = ......
但是想想在70年代末,80年代初,我們并沒(méi)有操作系統和消息循環(huán),甚至鼠標的光標都需要我們的UI系統來(lái)自行繪制,所以我們面對的應該是類(lèi)似下面的局面:
mouse.onclick = ......mouse.onmove = ......
當鼠標點(diǎn)擊事件發(fā)生后,我們需要通過(guò)View的信息將點(diǎn)擊事件派發(fā)到正確的View來(lái)處理。假如我們面對的是鼠標、鍵盤(pán)驅動(dòng)這樣的底層環(huán)境,我們就需要一定的機制和系統來(lái)統一處理用戶(hù)輸入并且分配給正確的View或者M(jìn)odel來(lái)處理。這樣也就不難理解為什么經(jīng)典MVC中稱(chēng)"Controller是用戶(hù)和系統之間的鏈接"。
因為現在的多數環(huán)境和UI系統設計思路已經(jīng)跟1979年完全不同,所以現代一些喜好生搬硬套的"MVC"實(shí)現者常常會(huì )認為Controller的輸入來(lái)自View,以至于畫(huà)出Model、View、Controller之間很奇葩的依賴(lài)關(guān)系:
我們來(lái)看看Trygve Reenskaug自己畫(huà)的圖(這惡趣味的骷髏啊……):
值得一提的是,其實(shí)MVC的論文中,還提到了"editor"這個(gè)概念。因為沒(méi)有出現在標題中,所以editor聲名不著(zhù)。MVC論文中推薦Controller想要根據輸入修改View時(shí),從View中獲取一個(gè)叫做editor的臨時(shí)對象,它也是一種特殊的Controller,它會(huì )完成對View和View相關(guān)的Model的修改操作。
控件系統
MVC是一種非常有價(jià)值的架構思路,然而時(shí)代在變遷,隨著(zhù)以windows系為代表的WIMP(window、icon、menu、pointer)風(fēng)格的應用逐漸成為主流,人們發(fā)現,View和Controller某些部件之間的局部性實(shí)際上強于Controller內部的局部性。于是一種叫做控件(control)的預制組件開(kāi)始出現了。
控件本身帶有一定的交互功能,從MVC的視角來(lái)看,它既包含View,又包含Controller,并且它通過(guò)"屬性",來(lái)把用戶(hù)輸入暴露給Model。
Controller的輸入分配功能,則被操作系統提供的各種機制取代:
指針系統:少數DOS時(shí)代過(guò)來(lái)的程序員應該記得,20年前的程序中的“鼠標箭頭”實(shí)際上是由各個(gè)應用自己繪制的,以MVC的視角來(lái)看,這應當屬于一個(gè)"PointerView"的職責范疇。但是20世紀以后,這樣的工作基本由操作系統的底層UI系統來(lái)實(shí)現了。
文本系統:今天我們幾乎不需要再去關(guān)心文本編輯、選中、拖拽等邏輯,對web程序員可以嘗試自己用canvas寫(xiě)一個(gè)文本編輯框來(lái)體驗一下上個(gè)時(shí)代程序員編寫(xiě)程序的感受。你會(huì )發(fā)現,選中、插入/覆蓋模式切換、換行、退格、雙擊、拖拽等邏輯異常復雜,經(jīng)典MVC模式中通常使用TextView和TextEditor配合來(lái)完成這樣的工作,但是今天幾乎找不到需要我們自己處理這些邏輯的場(chǎng)景。
焦點(diǎn)系統:焦點(diǎn)系統通過(guò)響應鼠標、tab鍵等消息來(lái)使得控件獲得操作系統級唯一的焦點(diǎn)狀態(tài),所有的鍵盤(pán)事件通常僅僅會(huì )由擁有焦點(diǎn)的控件來(lái)響應。在沒(méi)有焦點(diǎn)系統的時(shí)代,操作系統通常是單任務(wù)的,但是即使是單一應用,仍然要自己管理多個(gè)Controller之間的優(yōu)先權和覆蓋邏輯,焦點(diǎn)系統不但從技術(shù)上,也從交互設計的角度規范化了UI的輸入響應,而最妙的是,焦點(diǎn)系統是對視覺(jué)障礙人士友好的,現在頗多盲人用讀屏軟件都是強依賴(lài)焦點(diǎn)系統的。
所以時(shí)至今日,MVC,尤其是其中Controller的功能已經(jīng)意義不大,若是在控件系統中,再令所有用戶(hù)輸入流經(jīng)一個(gè)Controller則可謂不倫不類(lèi)、本末倒置。MVVM的提出者,微軟架構師John Gossman曾言:“我傾向于認為它(指Controller)只是隱藏到后臺了,它仍然存在,但是我們不需要像是1979年那樣考慮那么多事情了”
MVP
1996年,Taligent公司的CTO,Mike Potel在一篇論文中提出Model-View-Presenter的概念。
在這個(gè)時(shí)期,主流的View的概念跟經(jīng)典MVC中的那個(gè)“永遠不應該知道用戶(hù)輸入”的View有了很大的差別,它通常指本文中所述的控件,此時(shí)在Mike眼中,輸入已經(jīng)是由View獲得的了:
Model-View-Presenter是在MVC的基礎上,進(jìn)一步規定了Controller中的一些概念而成的:
對,所以,不論你按照Mike還是Trygve的理解方式,MVP和MVC的依賴(lài)關(guān)系圖應該是一!模!一!樣!的!因為Mike的論文里說(shuō)了“we refer to this kind(指應用程序全局且使用interactor, command以及selection概念的) of controller as a presenter”。presenter它就是一種Controller??!
把依賴(lài)關(guān)系畫(huà)成這樣也是醉了??!不管你信不信我反正是不信??!
標記語(yǔ)言和MVVM
隨著(zhù)20世紀初web的崛起,HTML跟JS這樣標記語(yǔ)言+程序語(yǔ)言的組合模式開(kāi)始變得令人注目。逐漸推出的Flex、Sliverlight、QT、WPF、JSF、Cocoa等UI系統不約而同地選擇了標記語(yǔ)言來(lái)描述界面。
在這樣的架構中,View(或者說(shuō)叫控件,不但是從依賴(lài)關(guān)系上跟程序的其他部件解耦,而且從語(yǔ)言上跟其它部分隔離開(kāi)來(lái)。
標記語(yǔ)言的好處是,它可以由非專(zhuān)業(yè)的程序員產(chǎn)生,通過(guò)工具或者經(jīng)過(guò)簡(jiǎn)單培訓,一些設計師可以直接產(chǎn)生用標記語(yǔ)言描述的UI。想要突破這個(gè)限制使得View跟其它部分異常耦合可能性也更低。
然而這樣的系統架構中,MVC和MVP模式已經(jīng)不能很好地適用了。微軟架構師John Gossman在WPF的XAML模式推出的同時(shí),提出了MVVM的概念。
WPF得MVVM正式說(shuō)明了它的View的概念跟MVC中的View的概念的區別。這里簡(jiǎn)單畫(huà)了一下:

在MVVM模式中,數據綁定是最重要的概念,在MVC和MVP中的View和Model的互相通訊,被以雙向綁定的方式替代,這進(jìn)一步把邏輯代碼變成了聲明模式。
結語(yǔ)
從經(jīng)典MVC到MVVM,UI架構經(jīng)過(guò)數次重大變遷,一些概念也在不斷變化,架構和底層環(huán)境互相影響、適配,我認為時(shí)至今日,經(jīng)典MVC已經(jīng)不再是UI架構的正常選項。
更糟糕的是,今天無(wú)數經(jīng)過(guò)演繹的MVC實(shí)現(如backbone)和科普文,要么是原本作者概念已經(jīng)很混亂,摻雜私貨,要么為了適配現代的標記語(yǔ)言和控件模式,自己修改了經(jīng)典MVC中的一些概念和耦合關(guān)系。實(shí)際上今天MVC已經(jīng)沒(méi)法作為一種交流的標準詞匯了。
寫(xiě)此文,希望大家能了解些歷史上的發(fā)展歷程,莫被不嚴謹的文章誤導。
聯(lián)系客服