多形態MVC式Web架構的分類
關鍵要點
-
MVC已成為每一代軟件開發人員所最早接觸到的軟件開發原則之一。
-
MVC應被視為一種通用的架構原則和方法。
-
MVC三元組件的語義隨架構環境的不同而變化。
-
可將基于HTTP的Web MVC(WMVC)分成三個不同的類別:sWMVC、dWMVC和pWMVC。
-
隨著近期技術的進步,異步且實時觀察變化的“事件循環”可用于WMVC應用的實現。
引言
MVC( 模型-視圖-控制器 ,Model-View-Controller)最初用于設計和實現狹義的桌面圖形用戶界面(GUI)應用開發。經典的MVC與面向對象的程序開發方法一樣,已成為每一代軟件開發人員所最早接觸到的軟件開發原則之一。雖然MVC對當今的工業界有著如此重要的影響,但是在日益互聯計算的時代,很明顯MVC的內涵已 迷失了其精準性 。這在過去20年間對于WUI(Web圖形界面,Web Graphical Interface)開發領域尤其是如此。基于以上原因,本文意在對MVC的起源做概要地闡述之后,進而深入地探討基于Web的MVC的演進和變化。
在WUI的應用場景下,原始MVC及MVC三元組中成員對象的歷史意義和內涵在不斷地演變和轉變形態。出于消除任何概念上的混淆的考慮,在本文的探討中將使用“WMVC”一詞表示基于Web的MVC式架構模式。大多數技術平臺的WMVC特性正處于不斷地改進之中,這包括Microsoft的 ASP.NET MVC 、PHP的 Symfony 、Python的 Django 、Ruby的 Merb 、Java的 JSR 371 等。驅動這些平臺改進的原則,很大程度上在于JavaScript已可由客戶端瀏覽器運行。此外,不少新的網絡協議充實了服務器-客戶間的通信。
自JavaScript被 XMLHttpRequest 賦予新生以來,它就成為WUI開發中情有獨鐘的技術。在過去的數年內,就有超過二十種 基于WMVC的JavaScript應用萌芽發展,其中包括 Dojo 、 Angular 、 Ember 、 Backbone 和 React 等。即使不是全部的也是絕大部分的框架都是側重于客戶端組件的交互,對于WMVC視圖和控制器的組成對象而言尤其是如此。自然而言,WUI開發方法上的革新再一次引發了針對MVC亦或WMVC的大量討論。這些討論時常是十分激烈的,通常側重于某個特定的方面,或基于某個特定的環境。進而使得MVC(WMVC)衍生出一些主要差異在于控制器對象的變體,其中包括 MVA 、 MVP 、 MVVM 、 Flux 、 Redux 和SAM等。這些MVC變體時常被統稱為“MV*”,其中的“*”表示了各變體間的差異主要在于視圖和控制器間的交互方式。通常并不將表示現實世界視圖對象的模型組件整體地列入考慮中,或僅是在Web應用方案中將模型作為MVC三元組關系里的被動參與者。
自MVC概念于四十多年前被提出以來,MVC模型很有可能已經歷了最重要的改變。在本文的探討中,我們對MVC模型做了一個寬泛的定義,這個定義中涵蓋了駐留內存的模型對象(例如 記錄集對象 ),還有用于支撐對象的 SoR (主數據記錄系統,System of Record)中的源數據、源文檔、源文件和原始信號,以及所有把它們同步和聚集到一起的過程。模型數據倉庫的存儲形式已從小型 軟盤 發展到 RDBMS 和 MMDBMS (多模數據庫管理系統,multi-model database management system)。早期模型數據倉庫是與駐留內存的模型對象共處一處的,這些模型對象是獨立存在于各個用戶桌面之上的。現在模型數據倉庫使用寬帶連接、分布式或基于云的系統,其部署可遠離域對象。存儲在這種外部環境中的數據,可以被企業生態系統的多個系統修改,也可以被消費者應用的數以千計的用戶修改。這種使用場景上的根本差異,已經在根本上地改變了模型對象的行為,進而改變了模型對象與MVC三元組中的另兩個成員間的通信和交互。
原型MVC
oMVC (原型MVC,Original MVC)是由挪威計算機科學家Trygve Reenskaug于1978年 提出 ,當時他工作于著名的 Xerox PARC 研究中心 Smalltalk 團隊中。在oMVC的概念初步成型后,最初被實現為 Smalltalk-80類庫 的一部分,用于桌面GUI的建立。
在那個時代,桌面應用遠非當前這樣是日常家居中的常見物品,每個應用需要獨立運行于一臺機器上,而每臺機器的存儲是有限的并且是各自獨立的。正如在圖1中所示,對oMVC模型對象的任何操作都完全由用戶行為通過控制器所觸發,MVC三元組在受控的環境中進行通信、同步并保持狀態。控制器的主要作用是維持用戶和系統之間的聯系(參見圖1)。控制器實現對相關GUI組件的部署,并在屏幕上將這些GUI組件展現給用戶。在 Win95出現之前 的年代中,這是一個具有挑戰性的任務,因為當時 MS-DOS 依然是占據主要地位的操作系統。在oMVC模型中,一旦用戶產生了某種動作,例如菜單選取、在輸入框中輸入、按鈕點擊等,控制器就會轉化這些動作為對應的改變消息,向模型傳遞這些消息,并對消息進行處理。
圖1展示了獨立桌面環境中的oMVC。圖中顯示了作為模型的組成部分的本地軟盤數據存儲。oMVC中控制器和視圖具有成對出現的關系,但是模型的改變并不在兩者間直接產生通信。控制器和視圖知道模型的狀態,但是反之并非如此。
一旦模型從控制器獲取了變更通知,它并不直接通過調用去更新所涉及的視圖。在模型-視圖的關系中,變更通知的獲取是通過每個獨立的參與者之間的相互注冊實現。一旦一方發生了變更,就會生成一個事件,對方就會采取相應的動作作為響應。在圖1中,視圖是附屬于模型的,對模型進行觀察。一旦控制器觸發了模型變更事件,視圖必須去確保自身顯示也按需更新,以相應地反映出模型的狀態。更新模型的通知信號也可由視圖自身生成。這種視圖與模型之間的 觀察 (或訂閱)和通知關系,有助于模型和視圖間的解耦,使得多個視圖可隸屬于同一模型,進而可提供不同的表示。
在圖1中值得注意的是,控制器并非直接地改變視圖。在Smalltalk社區及其它后續的桌面GUI應用庫中,通常將視圖和控制器看成一對耦合的對象。視圖使用具有特定控制器類型的實例實現預期的響應。為創建所期望的行為,控制器還可以在不同情景中 策略性地 、動態地切換類型。這樣的視圖-控制器對可以嵌套于 復合 層次結構中(如圖2A所示)。在該層次結構中的父輩之間、子女之間及父子之間,視圖-控制器組件都可以進行交互和通信。很多情況下,層次結構中的每個獨立視圖-控制器的子女組件僅處理部分的模型對象。此外,從oMVC組合的角度看,模型也可以使用層次結構的形式進行組織,這樣 MVC三元組作為一個整體 構成 層次結構中的父子關系 ,如圖2B所示。
(點擊放大圖像)
圖2左圖是oMVC的復合表示,右圖是 PAC (顯示-抽象-控制,Presentation-Abstraction-Control)的表示。
總而言之,oMVC設計范例是由一系列的 GoF設計模式 所組成,尤其是其中包括了 觀察者模式 、 策略模式 和 復合模式 。在早期的桌面應用庫中,oMVC域架構和模式的設計意圖得以保持,即模型組件由應用域對象和數據存儲所組成,其中存儲多是本地的或是受限的。在oMVC三元組類的行為中,應用域行為的維護和廣播起著核心的作用。oMVC的一個關鍵假設是模型的穩定性,該假設在上世紀七十和八十年代的桌面應用情景中顯然是正確的。但是在WMVC領域,模型時常發生改變通常是一種常態。直至近些年,向用戶實時廣播變更(類似于oMVC所實現的)所需的技術基礎才得以實現。
WMVC的分類
具有諷刺意味的是,雖然直到上世紀九十年代,尤其是在Win95出現之后的年代,桌面計算機開始進入普通百姓家并得到普及,但是傳統的桌面應用卻因為因特網互聯的Web應用開始統治了業界而逐漸退居幕后。不同于安裝并于運行于終端用戶計算機上的桌面應用,Web應用是宿主于遠離用戶的服務器上,創建了客戶-服務器的關系。在本文的其后內容中,我們將瀏覽器(browser)和客戶(client)這兩個概念互換使用。根據瀏覽器和服務器相對于WMVC三元組對象的部署位置和執行方式的不同,可將WMVC明確地分組為:
-
服務器端WMVC (Server-side WMVC,sWMVC):所有WMVC的組件位于服務器上,并在服務器上執行。
-
雙重WMVC(Dual WMVC,dWMVC):WMVC組件分布于瀏覽器和服務器之間。通信可由客戶或者服務器端發起。
-
點對點WMVC(Peer-to-Peer WMVC,pWMVC):這種架構中沒有集中式服務器。所有WMVC組件位于客戶端,在客戶端執行。pWMVC可具有自己的沙箱SoR。
服務器端WMV(sWMVC)
在sWMVC模型中,用戶使用瀏覽器作為瘦客戶,通過無狀態的請求-響應HTTP協議訪問應用(如圖3所示)。客戶向服務器發送HTTP請求或輸入內容,接收并顯示整個更新的Web頁面(或是其它的文檔)。一旦頁面被加載以后,各頁面組件間就很少有交互了,頁面成為靜止的。
在這種瘦客戶-服務器范式的sWMVC架構中,應用SoR版本庫外部化為一種集中式環境。它與應用服務器內存中的域對象是相互分離的。服務器和數據版本庫都是遠離用戶瀏覽器部署的(如圖3所示)。SoR存儲常常是由一個或多個關系數據庫這樣的數據源所組成。鑒于數據已經外部化了,帶外進程或不同的用戶都可對數據進行更新。數據的變更只會從控制器流向模型(參見圖3);當SoR中數據被不同的用戶或系統改變時,并不向應用服務器發送入站數據變更通知。不同于oMVC,模型及其所關聯的視圖間不再有任何的直接聯系和必要的同步。由于視圖不再反映模型的狀態,這就需要用戶手動地發起新的HTTP請求去同步和刷新視圖。因此sWMC中的“s”,也可指代這種WMVC范例的靜態(static)或是陳舊(stale)的本質特性。
圖3sWMVC范例的一種表示。圖中顯示了由服務器駐留內存的域對象模型(M)外部化而得到的SoR。不同于oMVC,控制器不再與用戶交互,而是用于協調模型與視圖間的通信。模型數據的變更是單向流動到外部數據存儲中的。
WMVC的模型可簡述為一種分層架構(如圖4所示)。架構的最頂層模型表示了在視圖及其相關的控制器這個關系對之間的契約關系。為滿足該契約,在處理棧中可包含數個可變的業務邏輯和數據訪問組件。該契約用于所有與視圖相關信息的連接,其中的信息可能直接來自本地SoR,或是數據云,或是其它真實世界中的數據源,例如探測器和數據提供系統。
圖4WMVC模型的示意圖。圖中顯示WMVC的組成包括了多個架構層次,以及來自本地或遠程可訪問環境中的可變數據源。
相對于在oWMVC中的意義和內容(如圖3所示)而言,三元組對象間的關系和通信發生了根本上的轉變。與控制器在用戶和oMVC系統(圖1)間所起的作用不同,sWMVC的控制器承擔了在更高層級上協調視圖和模型的角色(參加圖3)。視圖和模型間的通信通過控制器發生。用戶與視圖進行交互,將模型與模型視圖關聯的行為邏輯包含在控制器中,由控制器負責管理輸入、更新模型并產生適當的輸出。
Web應用的架構環境與桌面應用的有所不同,對于 將MVC引入 到 早期Web應用架構 的設計中,雖然這在本質上忽視了MVC的原生結構。但是這種引入反而接收了MVC模型的基本理念,即將這三個相互作用的、多變責任的對象類進行相互分離是十分重要的。該做法將oMVC范例提升為UI設計中在更加通用層次上的架構原則,增加了對任意類型UI應用的靈活性和可維護性。
sWMVC中通常包含有多種設計模型,其中也包括在oMVC中所使用的設計原則。例如,各個用例的 控制器 原則和行為可能都是不同的,包括 中介者模式 、 調度者模式 、使用 狀態模式 和 模板方法模式 的 策略模式代理 等。但是在oMVC中,觀察者模式在觸發三個對象類型間的通信中起著關鍵的作用,尤其是當該模式與視圖做相關的更新時。在sWMVC實現中,觀察者的作用被縮減了。這樣導致了sWMVC的靜態和陳腐的特征。直至近些年,技術的進展才使得交互式和富Web用戶體驗成為可能。
雙重WMVC(dWMVC)
在Web時代的早期,由于瀏覽器的普遍使用,為使現有的桌面交互應用支持Web做出了不懈的努力。這些工作的一個成果體現為 Microsoft的Outlook Web項目所研發的 一種基于Web的新組件,該組件允許客戶端腳本發布異步HTTP請求到服務器。該工作引導了 XMLHttpRequest (XHR)協議的建立和標準化。該協議是至上世紀末為止最具有革命性的工作。XMLHttpRequest隨后成為 Ajax 技術的基本原則。
當前,基于這種技術的架構使得dMWVC的視圖-控制器對可以動態分布,并可安裝到用戶桌面、移動設備或其它設備的瀏覽器上。瀏覽器組件與服務器上模型間的異步通信,用于同步給定的或者所有的視圖元素的dWMVC三元對象組狀態,進而提供給用戶對現實世界或模型對象的最新認知。這種技術的引入使得XHR切實地豐富了客戶應用,為瀏覽器用戶帶來了交互式的用戶體驗。
XHR技術還引發了 單頁應用 (SPA)開發技術的發展。類似于oMVC應用,SPA是駐留在單一頁面上的Web網站,提供了無縫的瀏覽體驗。對于用戶而言,SPA看上去在從一個頁面到另一個頁面時并沒有任何頁面重載,對不同頁面渲染所需的資源是在所需時由幕后的服務器動態且異步加載的。SPA和這種dWMVC應用的交互行為的組合使此類范式劃分為了 富互聯網應用 (RIA)的最新條目。
就XHR協議自身而言,從客戶端的視圖-控制器對象到服務器端模型間的通信依然僅是單向的通信,需要由視圖發起某種類型的 輪詢機制 去探測模型上的更改。輪詢是一種資源密集型操作,因而成為影響性能的一個關注點。類似于圖1所示的oMVC,在理想情況下模型中的任何更改應會被實時發布到、或是廣播到所有相關的視圖-控制器組件中。圖5顯示了dWMVC架構的視圖和模型間的雙向異步同步(通過控制器)。該機制提供了完全動態的狀態同步,這種同步基于dWMVC組件間的訂閱-發布機制。一些近期的技術發展,其中包括 服務器發送事件 (Server-Sent Events,SSE)、 WebSocket 和入站數據庫通知技術等,使得該同步操作成為可能。
圖5dWMVC的示意圖。圖中顯示了三元組對象在客戶和服務器間的分布。由SoR發起的入站更改通知導致了模型和視圖間的實時雙向更新。
SSE機制作為 HTML5 的組成部分,允許服務器端組件異步啟動,并將數據從服務器端組件實時推送到瀏覽器。客戶端組件可以使用SSE發起請求,向服務器申請建立一個非傳統的HTTP連接。一旦客戶端組件接收到所發起的請求,它繼續對隨后的服務器響應進行監聽。與此同時,服務器保持同一客戶-服務器初始連接是活躍的。一旦新的數據可用,服務器無需客戶的額外請求,就立刻通過該初始連接將這些數據推送給客戶。這樣,SEE給出了一種從服務器到客戶瀏覽器的解決方案,該解決方法使用了異步的發布-訂閱事件通知。
WebSocket是一種提供瀏覽器和服務器間全雙工連接的通信協議。當客戶發送初始請求到服務器時,WebSocket通知服務器該HTTP連接可能會升級為全雙工的TCP/IP WebSocket連接,通知使用了一種特殊的HTTP報頭。一旦WebSocket連接被建立,就可在需要時用于在瀏覽器和服務器間相互發送數據。
使用SSE和WebSocket通信協議,服務器可以異步地將模型駐留內存的更改發布到瀏覽器。但是正如前面所討論過的,模型架構的分層可能會跨越服務器的邊界,并可能包括應用服務器之外的外部SoR(參見圖4)。由于SoR中的數據記錄可被其他應用或用戶修改,因此每當這樣的帶外更改發生時,SoR應具有 變化數據捕獲 (change data capture,CDC)機制去探測并捕獲更改,實時地發起并推送入站數據更改到應用服務器,實現端到端的雙向發布-訂閱通信模型(如圖5和圖6所示)。在圖6中,dWMVC輪轂的中心表示了共享的SoR和CDC數據源。數據的實時同步由數據源和相關駐留內存域模型對象之間的雙向交互所維持。在圖6中,每個輪輻間的微型dWMV表示了一個獨立的業務應用(集成的企業生態系統中),或是一個獨立的應用用戶。
圖6dWMVC輪圖。圖中顯示了由SoR發起的入站更改通知,并顯示所引發的模型和所有視圖間的實時雙向更新情況(以微型WMVC展示)。
基于Web的架構棧中加入了XHR-Ajax、SSE和WebSocket等技術,還有數據庫廠商提供了數據庫入站通信能力,所有這些一起使得傳統oMVC中視圖和模型間的雙向交互通信在dWMVC中得到了復興。越來越多的數據庫廠商,包括 PostgreSQL 、 Oracle 等傳統關系數據庫廠商和 RethinkDB 、 Cassandra 等 NoSQL 數據庫廠商,已經實現或者規劃去提供CDC機制,以改進應用服務器的入站推送通知。
點對點WMVC(pWMVC)
對于上面所論及的兩種WMVC,它們的架構語義都是基于 客戶-服務器范例 的,即用戶瀏覽器向服務器發送HTTP請求,取回服務器端的內容,服務器則回應以包含請求信息的一個或更多的響應。這類方法中,服務器負責存儲,并發送所有內容及對所有請求的響應。但是這樣的集中式方法可能會導致性能上的瓶頸。因為為了支持所有可能的請求負載,需要對服務器基礎設施的資源進行適當地擴展和復制。當前由于高頻度實時內容發布需求在數量上日益增長,這類方法會產生問題,尤其是在(意料之外的)高通量負載的期間。最優的系統無疑是那種能以去中心化的方式支持高質量終端用戶體驗的系統,這樣的系統可以使用戶用最短的路由和時間獲取到數據。借助于 點對點 (Peer-to-peer,P2P)數據交換及通信,終端用戶可以從其它的用戶那里交互、檢索和接收內容。無疑,這樣的架構繞開或降低了集中式服務器的負載和潛在瓶頸問題。
傳統的點對點系統需要用戶顯式地安裝專用的桌面應用或插件。在 WebRTC (Web實時通信,Web Real-Time Communication)協議被標準化并被瀏覽器支持之前,瀏覽器本身并不具備使對等系統的工作直接相互通信的能力。現在WebRTC標準已被大多數的瀏覽器所支持。它是一種API定義,提供了無服務器的瀏覽器到瀏覽器(瀏覽器P2P)直接數據交換和通信范例。WebRTC對Web應用引入了點到點的解決方案,它允許Web瀏覽器打開到其它瀏覽器的直接通信通道,無需對每個Web請求-響應的集中式服務場景進行處理(參見圖7和圖8)。
圖7pWMVC如圖所示,圖中顯示了位于客戶端(瀏覽器)內、或由客戶端所控制的所有三元組組件。
在pWMVC模型中,所有的三元組組件位于并執行于客戶端及相關終端用戶的沙箱中(如圖7所示)。沙箱中包括用戶本地或基于云的SoR存儲,這樣的存儲可以被pWMVC應用訪問。在圖8中,輪輻間的每個微型pWMVC都代表了一種獨立用戶瀏覽器環境。與圖6相比,為便于持續進行的Web通信,pWMVC輪圖中并未涉及集中式服務器和SoR架構。互聯瀏覽器間的微型pWMVC組件狀態可使用WebRTC通信協議保持同步。
圖8pWMVC輪圖。圖中顯示了由獨立用戶瀏覽器所發起的直接無服務器P2P變更通知,以及該通知如何導致其它的對等端視圖進行實時更新。圖中“M”指代內存中模型對象和用戶SoR。
總結
MVC本身應該被視為是一種無需考慮任何語義的設計原則或方法論。MVC的簡要內涵在于,任何類型的UI應用都可被分解為三套相互作用的對象類。在MVC所應用的場景中,應該審查該三元對象類型組的行為。為更好地理解MVC概念,在對架構和特定域程序庫進行實際設計和實現應用時,應使用適當的命名注釋。
WMVC可看成一種獨特的原理圖,用于在無狀態HTTP域的場景中基于MVC方法論的開發。WMVC可區分sWMVC、dWMVC和pWMVC這三種不同的類別。這些類別在機制上不同于oMVC,即原型MVC。考慮到標準化的網絡協議、由特定數據庫技術所提供的專用入站通信等這樣的最新技術發展,基于觀察更改的MVC式“事件循環”可以滿足基于Web應用的需求。這使得WMVC當前可為瀏覽器用戶實現具有完全交互的實時豐富WUI體驗。
來自:http://www.infoq.com/cn/articles/mvc-web-architecture-polymorphism