談談UI架構設計的演化

@寒冬winter發表於2015-02-12

經典MVC

在1979年,經典MVC模式被提出。

在當時,人們一直試圖將純粹描述思維中的物件與跟計算機環境打交道的程式碼隔離開來,而Trygve Reenskaug在跟一些人的討論中,逐漸剝離出一系列的概念,最初是Thing、Model、View、Editor。後來經過討論定為Model、View和Controller。作者自言“最難搞的就是給這些架構元件起名字”。

因為當時的軟體環境跟現在有很大不同,所以經典MVC中的概念很難被現在的工程師理解。比如經典MVC中說:“view永遠不應該知道使用者輸入,比如滑鼠操作和按鍵。”對一個現代的軟體工程師來說,這聽上去相當不可思議:難道監聽事件不需要類似這樣的程式碼嗎?

view.onclick = ……

但是想想在70年代末,80年代初,我們並沒有作業系統和訊息迴圈,甚至滑鼠的游標都需要我們的UI系統來自行繪製,所以我們面對的應該是類似下面的局面:

mouse.onclick = ……mouse.onmove = ……

當滑鼠點選事件發生後,我們需要通過view的資訊將點選事件派發到正確的view來處理。假如我們面對的是滑鼠、鍵盤驅動這樣的底層環境,我們就需要一定的機制和系統來統一處理使用者輸入並且分配給正確的view或者model來處理。這樣也就不難理解為什麼經典MVC中稱”controller是使用者和系統之間的連結”。

因為現在的多數環境和UI系統設計思路已經跟1979年完全不同,所以現代一些喜好生搬硬套的”MVC”實現者常常會認為controller的輸入來自view,以至於畫出model、view、controller之間很奇葩的依賴關係:

我們來看看Trygve Reenskaug自己畫的圖(這惡趣味的骷髏啊……):

值得一提的是,其實MVC的論文中,還提到了”editor”這個概念。因為沒有出現在標題中,所以editor聲名不著。MVC論文中推薦controller想要根據輸入修改view時,從view中獲取一個叫做editor的臨時物件,它也是一種特殊的controller,它會完成對view和view相關的model的修改操作。

控制元件系統

MVC是一種非常有價值的架構思路,然而時代在變遷,隨著以windows係為代表的WIMP(window、icon、menu、pointer)風格的應用逐漸成為主流,人們發現,view和controller某些部件之間的區域性性實際上強於controller內部的區域性性。於是一種叫做控制元件(control)的預製元件開始出現了。

控制元件本身帶有一定的互動功能,從MVC的視角來看,它既包含view,又包含controller,並且它通過”屬性”,來把使用者輸入暴露給model。

controller的輸入分配功能,則被作業系統提供的各種機制取代:

  • 指標系統:少數DOS時代過來的程式設計師應該記得,20年前的程式中的“滑鼠箭頭”實際上是由各個應用自己繪製的,以MVC的視角來看,這應當屬於一個”PointerView”的職責範疇。但是20世紀以後,這樣的工作基本由作業系統的底層UI系統來實現了。
  • 文字系統:今天我們幾乎不需要再去關心文字編輯、選中、拖拽等邏輯,對web程式設計師可以嘗試自己用canvas寫一個文字編輯框來體驗一下上個時代程式設計師編寫程式的感受。你會發現,選中、插入/覆蓋模式切換、換行、退格、雙擊、拖拽等邏輯異常複雜,經典MVC模式中通常使用TextView和TextEditor配合來完成這樣的工作,但是今天幾乎找不到需要我們自己處理這些邏輯的場景。
  • 焦點系統:焦點系統通過響應滑鼠、tab鍵等訊息來使得控制元件獲得作業系統級唯一的焦點狀態,所有的鍵盤事件通常僅僅會由擁有焦點的控制元件來響應。在沒有焦點系統的時代,作業系統通常是單任務的,但是即使是單一應用,仍然要自己管理多個controller之間的優先權和覆蓋邏輯,焦點系統不但從技術上,也從互動設計的角度規範化了UI的輸入響應,而最妙的是,焦點系統是對視覺障礙人士友好的,現在頗多盲人用讀屏軟體都是強依賴焦點系統的。

所以時至今日,MVC,尤其是其中controller的功能已經意義不大,若是在控制元件系統中,再令所有使用者輸入流經一個controller則可謂不倫不類、本末倒置。MVVM的提出者,微軟架構師John Gossman曾言:“我傾向於認為它(指controller)只是隱藏到後臺了,它仍然存在,但是我們不需要像是1979年那樣考慮那麼多事情了”

MVP

1996年,Taligent公司的CTO,Mike Potel在一篇論文中提出Model-View-Presenter的概念。

在這個時期,主流的view的概念跟經典MVC中的那個“永遠不應該知道使用者輸入”的view有了很大的差別,它通常指本文中所述的控制元件,此時在Mike眼中,輸入已經是由view獲得的了:

Model-View-Presenter是在MVC的基礎上,進一步規定了Controller中的一些概念而成的:

對,所以,不論你按照Mike還是Trygve的理解方式,MVP和MVC的依賴關係圖應該是一!模!一!樣!的!因為Mike的論文裡說了“we refer to this kind(指應用程式全域性且使用interactor, command以及selection概念的) of controller as a presenter”。presenter它就是一種controller啊!

把依賴關係畫成這樣也是醉了啊!不管你信不信我反正是不信啊!

標記語言和MVVM

隨著20世紀初web的崛起,HTML跟JS這樣標記語言+程式語言的組合模式開始變得令人注目。逐漸推出的Flex、Sliverlight、QT、WPF、JSF、Cocoa等UI系統不約而同地選擇了標記語言來描述介面。

在這樣的架構中,view(或者說叫控制元件,不但是從依賴關係上跟程式的其他部件解耦,而且從語言上跟其它部分隔離開來。

標記語言的好處是,它可以由非專業的程式設計師產生,通過工具或者經過簡單培訓,一些設計師可以直接產生用標記語言描述的UI。想要突破這個限制使得view跟其它部分異常耦合可能性也更低。

然而這樣的系統架構中,MVC和MVP模式已經不能很好地適用了。微軟架構師John Gossman在WPF的XAML模式推出的同時,提出了MVVM的概念。

WPF得MVVM正式說明了它的view的概念跟MVC中的view的概念的區別。這裡簡單畫了一下:

在MVVM模式中,資料繫結是最重要的概念,在MVC和MVP中的view和model的互相通訊,被以雙向繫結的方式替代,這進一步把邏輯程式碼變成了宣告模式。

結語

從經典MVC到MVVM,UI架構經過數次重大變遷,一些概念也在不斷變化,架構和底層環境互相影響、適配,我認為時至今日,經典MVC已經不再是UI架構的正常選項。

更糟糕的是,今天無數經過演繹的MVC實現(如backbone)和科普文,要麼是原本作者概念已經很混亂,摻雜私貨,要麼為了適配現代的標記語言和控制元件模式,自己修改了經典MVC中的一些概念和耦合關係。實際上今天MVC已經沒法作為一種交流的標準詞彙了。

寫此文,希望大家能瞭解些歷史上的發展歷程,莫被不嚴謹的文章誤導。其實本文的相當多觀點也是經過演繹的,所以我附上所有原始文獻連結,希望大家看了以後能有自己的判斷:)也歡迎大家據此指出我理解的錯誤之處。

相關文章