从Script到Code Blocks、Code Behind到MVC、MVP、MVVM
?
剛過(guò)去的周五(3-14)例行地主持了技術(shù)會(huì)議,主題正好是《UI層的設(shè)計(jì)模式——從Script、Code Behind到MVC、MVP、MVVM》,是前一天晚上才定的,中午花了半小時(shí)準(zhǔn)備了下就開(kāi)講了。
今天看到了大家在為MVVM knockout.js友(ji)好(lie)地交流,所以就整理下然后更擴(kuò)展地分享。
主要目的也不是為了爭(zhēng)論,畢竟只是正巧主題相近,原本的打算也就是一次技術(shù)分享并且記錄下來(lái)。
?
那么我們就按照大致的歷史進(jìn)程將這些概念進(jìn)行劃分:
- Script
 - Code Blocks、Code Behind
 - MVC、MVP、MVVM
 
我們知道的是現(xiàn)實(shí)的歷史發(fā)生順序并不如上,因?yàn)樗枷攵际窍嗨频?#xff0c;比如MVC很早很早就出現(xiàn)了,解釋型語(yǔ)言至今基本上也有很多分支而且在互聯(lián)網(wǎng)時(shí)代大行其道。
但我要說(shuō)的是:不要在意這些細(xì)節(jié)!
當(dāng)然了,這是玩笑,我的意思是,這些內(nèi)容我懶得應(yīng)該在另外獨(dú)立的主題探討,篇幅也有限。
?
?
Script
這里腳本的意思不是指當(dāng)時(shí)是用腳本開(kāi)發(fā),而是像寫(xiě)腳本一樣開(kāi)發(fā)。它們都有一個(gè)特點(diǎn):功能單一、管理單一、入口單一。
我們最早的程序是匯編,當(dāng)時(shí)的碼農(nóng)的工作是兼職,工作內(nèi)容是編寫(xiě)一套壽命不長(zhǎng)的機(jī)器控制指令,有些甚至是命令,比如至今依然保留的Command(亮點(diǎn)自尋):
到后來(lái)計(jì)算機(jī)被用于科學(xué)計(jì)算等,需求推動(dòng)了需要更高的開(kāi)發(fā)效率,所以我們有了高級(jí)語(yǔ)言。
那個(gè)時(shí)候碼農(nóng)其實(shí)多是數(shù)學(xué)家,程序的作用很簡(jiǎn)單,就是執(zhí)行一些數(shù)學(xué)計(jì)算,類似今天ICPC的一些算法問(wèn)題,比如Hello World:
main() {printf("hello,world\n"); }這時(shí)候,程序還可以被歸結(jié)為輸入到輸出的過(guò)程,我們還能去講講馮諾依曼模型。
在這個(gè)時(shí)代,開(kāi)發(fā)是指編寫(xiě)機(jī)器指令,甚至都不配用“開(kāi)發(fā)”這個(gè)詞來(lái)描述這項(xiàng)工作。
?
?
軟件、UI和Markup Language
在那個(gè)時(shí)代講UI等于放屁,根本不存在這種概念。但全賴我們有神器——摩爾定律。
但我個(gè)人認(rèn)為摩爾定律是不足以讓一個(gè)敲命令行的時(shí)代在幾十年間轉(zhuǎn)變成這種各類框架技術(shù)架構(gòu)實(shí)踐模式的時(shí)代,真正推動(dòng)計(jì)算機(jī)形成自有的工程學(xué)體系的是還有兩樣?xùn)|西就是:
- 人的能力并沒(méi)有變強(qiáng),至少?zèng)]有在同級(jí)數(shù)下變強(qiáng)。
 - 人類一定會(huì)物盡其用
 
因?yàn)槿说哪芰Σ](méi)有“跟上”機(jī)器,所以才會(huì)出現(xiàn)各種模式、方法、工具等等來(lái)補(bǔ)足人的不足,以最大地透支機(jī)器性能。就像我前幾天在閃存無(wú)聊時(shí)突然想到的一句:?架構(gòu)是對(duì)客觀不足的妥協(xié),規(guī)范是對(duì)主觀不足的妥協(xié)。
當(dāng)我們需要機(jī)器做的事情多了起來(lái),我們就沒(méi)辦法在一個(gè)芯片上解決所有事情,所以才會(huì)有馮諾依曼模型、計(jì)算機(jī)架構(gòu),沒(méi)辦法用一臺(tái)機(jī)器解決,所以才要互聯(lián)網(wǎng)、分布式、云計(jì)算。
同樣,隨著計(jì)算機(jī)的發(fā)展,要做的事情多了,就出現(xiàn)了軟件的概念。當(dāng)“開(kāi)發(fā)”正式化,我們需求的軟件就變得:功能繁雜、管理統(tǒng)一、多入口。
真正變化的不是客觀本質(zhì),而是需求。就像這里說(shuō)的“軟件入口”在客觀上我們還是只有一個(gè),原理上始終都只有一個(gè)啟動(dòng)程序、一個(gè)啟動(dòng)代碼片段。但“軟件的入口”,已經(jīng)從指代Main函數(shù)變成了指代起始UI,用戶已經(jīng)從指代專業(yè)人士變成了指代一般消費(fèi)者,先有軟件的需求,才有軟件的定義,而需求是在變化的。
一個(gè)軟件需要比當(dāng)時(shí)多幾個(gè)數(shù)量級(jí)的代碼:
- 客觀上我們沒(méi)辦法做一個(gè)能顯示所有代碼的顯示器
 - 主觀上我們沒(méi)辦法在超快速滾動(dòng)中看清所有代碼
 
所以我們需要添加索引、用多個(gè)文件組織代碼。
機(jī)器的發(fā)展和軟件的需求擴(kuò)大和細(xì)化,我們開(kāi)始出現(xiàn)了用戶界面(User Interface)的概念和最適合用于界面的語(yǔ)言——標(biāo)記語(yǔ)言(Markup Language)。當(dāng)然,ML不是為UI而生的,它只是十分適合UI,所以才和UI墜入愛(ài)河。
因?yàn)橛辛烁遀I的需求,所以代碼才正式被分化為描述做什么(業(yè)務(wù)邏輯)和有什么(UI)的兩部分,因?yàn)槲覀冮_(kāi)發(fā)時(shí)沒(méi)辦法在兩種思維方式下同時(shí)工作,開(kāi)發(fā)時(shí)的人腦是單線程的。我們所看到的同時(shí)進(jìn)行UI和邏輯開(kāi)發(fā)只不過(guò)是我們學(xué)會(huì)了在兩種模式下快速切換,看起來(lái)像同時(shí)進(jìn)行,而不是真正的同時(shí)進(jìn)行。同樣的情況也發(fā)生在不同的代碼片段的開(kāi)發(fā)中。
分化的情況除了UI,還發(fā)生在方方面面,比如數(shù)據(jù)操作、UI的對(duì)象和樣式分離,我們還是繼續(xù)從UI講下去吧。
?
?
Code Block和Code Behind(其實(shí)還有Code Inside,比如οnclick="javascript:alert('哎呀我*')")
UI和邏輯分開(kāi)了兩種語(yǔ)言來(lái)寫(xiě),但是它們也要放在同一個(gè)項(xiàng)目中,因?yàn)樗鼈冊(cè)揪褪且黄鸸ぷ鞯摹?/strong>即使是分開(kāi),也需要相連,因?yàn)檫@是它們本來(lái)要解決的問(wèn)題。
這時(shí)候我們出現(xiàn)的(通常的)解決方案就是Code Block和Code Behind。雖然從時(shí)間上似乎Code Block比Code Behind要早,有種感覺(jué)就是越新越好,但實(shí)質(zhì)上它們正交替地發(fā)展著,因?yàn)?strong>誰(shuí)也沒(méi)辦法解決UI和邏輯代碼分化后的一個(gè)哲學(xué)問(wèn)題——UI和邏輯是一起的,但是它們卻不是一起的。
?
Code Block能很好地處理UI和邏輯間在一起的關(guān)系,你在同一個(gè)地方可以同時(shí)維護(hù)UI和邏輯:
?
1 @model GM.OA.Finance2.Web.Models.FinancialBase.CurrencyModel2 @{3 ViewBag.Title = "EditCurrencyDrawer";4 Layout = "~/Views/Shared/_DrawerLayout.cshtml";5 }6 7 @section styles {8 <link href="/Content/base/table-form.css" rel="stylesheet" />9 <link href="/Content/base/drawer.bigtitle.css" rel="stylesheet" /> 10 }?
<a href="#" class="addcurrency oa-btn" oa-style="green">添加新幣別</a><script type="text/javascript">$(document).ready(function () {$('.addcurrency').click(function () {$.oa.drawer.openUrl('AddCurrencyDrawer/', 'addcurrency', {width: 300});});}); </script>?
Code Behind能很好地處理UI和邏輯各自分開(kāi)的關(guān)系,你可以讓UI和邏輯各自做好各自的事情:
?
<asp:Button ID="RemoveSelectedCurrency_Button" runat="server" Text="刪除選中幣別" OnClick="RemoveSelectedCurrency_Button_Click" /> <asp:Button ID="RemoveAllCurrencies_Button" runat="server" Text="刪除所有幣別" OnClick="RemoveAllCurrencies_Button_Click" /> 1 protected void RemoveSelectedCurrency_Button_Click(object sender, EventArgs e)2 {3 var currencyId = Currencies_ListBox.SelectedItem.Value;4 currencyManager.Remove(currencyId);5 }6 7 protected void RemoveAllCurrencies_Button_Click(object sender, EventArgs e)8 {9 currencyManager.RemoveAll(); 10 }?
因?yàn)榇嬖趦煞N實(shí)現(xiàn)方式,所以就存在了對(duì)比,因?yàn)榇嬖诹藢?duì)比,所以就存在了爭(zhēng)論。就像是Java和.NET、PHP和.NET、WebForm和MVC、Mac OS和Windows、iOS和Android、騰訊和所有其他互聯(lián)網(wǎng)公司,等等。
問(wèn)題不在哪個(gè)更好,而是我們要解決什么問(wèn)題。當(dāng)然,這聽(tīng)(ben)著(lai)像(jiu)是客氣話了。
真正在UI和邏輯分化后帶來(lái)的實(shí)質(zhì)問(wèn)題是:
- 是按邏輯和UI劃分地管理,還是按單界面的事務(wù)進(jìn)行劃分地管理
 
至少UI和邏輯剛分化的時(shí)代,在軟件上,我們還認(rèn)為同一項(xiàng)事務(wù)是基于同一個(gè)UI的一系列操作完成的。
在摩爾定律還持續(xù)發(fā)揮作用的時(shí)候,計(jì)算機(jī)領(lǐng)域依舊高速發(fā)展,所以通常我們還在為一樣事物爭(zhēng)論、思考、辯證的時(shí)候,它已經(jīng)發(fā)生了質(zhì)變了,不變的只是我們要解決的問(wèn)題。
?
?
事務(wù),以及界面、數(shù)據(jù)、事件、業(yè)務(wù)
在之前說(shuō)到過(guò)了,當(dāng)需求變得龐大,解決方案也會(huì)變得龐大;當(dāng)解決方案變得龐大,就會(huì)出現(xiàn)細(xì)分;當(dāng)出現(xiàn)細(xì)分,就會(huì)出現(xiàn)按哪種方式管理的問(wèn)題。
軟件從處理一件事務(wù)發(fā)展到了要處理許多事務(wù),各事務(wù)間有包含、順序、主次等等的關(guān)系,變得越來(lái)越復(fù)雜。因?yàn)閿?shù)據(jù)與邏輯龐大了,所以數(shù)據(jù)與邏輯就分離了,然后事件和業(yè)務(wù)分離了。
它們的關(guān)系已經(jīng)在我們還理得清之前持續(xù)發(fā)展而變得更加難理得清,但在一個(gè)時(shí)間點(diǎn)上,它們UI的領(lǐng)域大致分化成這些原子:
- 界面
 - 數(shù)據(jù)
 - 事件
 - 業(yè)務(wù)
 
你要細(xì)化的話會(huì)有更多繁雜的細(xì)節(jié),但相信這么寫(xiě)的話爭(zhēng)議性比較小。
當(dāng)一個(gè)問(wèn)題出現(xiàn)一次的時(shí)候它是一個(gè)問(wèn)題,當(dāng)一個(gè)問(wèn)題出現(xiàn)了無(wú)數(shù)次的時(shí)候它會(huì)成為歷史,當(dāng)一個(gè)問(wèn)題將會(huì)出現(xiàn)無(wú)數(shù)次的時(shí)候,它將需要一個(gè)明確的定義和解決方案。
其中,數(shù)據(jù)的更新和界面的更新這一特殊事件的問(wèn)題被放大了無(wú)數(shù)倍,因?yàn)樗霈F(xiàn)了無(wú)數(shù)次。
?
?
Model-View-Controller
在ASP還在奮斗的時(shí)候WebForm突然到來(lái),正如WebForm還在奮斗的時(shí)候MVC突然到來(lái)。當(dāng)然,我這里講的MVC還是最原始的MVC,因?yàn)镸VC在我們還在爭(zhēng)論的時(shí)候已經(jīng)發(fā)展了許多不同分支了。
有一點(diǎn)相信大家同意的就是,我們今天討論爭(zhēng)論的MVC、MVP、MVVM、Code Behind等等都源自于職能分化和規(guī)劃的思想與目的,MVC不是它們的開(kāi)始,但是一個(gè)很好的開(kāi)始。
相信MVC的模型大家很熟悉,也很容易找到,我們這里用一下某百科的圖:
我們可以看到的是,界面被分到了View,數(shù)據(jù)分到了載體Model上由Model“攜帶”,業(yè)務(wù)集中在Controller中,而推動(dòng)業(yè)務(wù)的事件由用戶與View交互,通過(guò)View向Controller發(fā)動(dòng)。
當(dāng)然,實(shí)現(xiàn)由很多種,每種細(xì)節(jié)上都有不同,所以我才只講也只能講大致的MVC。MVC的其中一個(gè)缺點(diǎn)便是沒(méi)有明確的定義,所以不同的實(shí)現(xiàn)(比如Struts和ASP.NET MVC)細(xì)節(jié)上都是不一樣的。
我們需要知道的是,MVC并不是像上面所說(shuō)的一些事情那樣是一種“必然的”結(jié)果,它是一系列必然結(jié)果問(wèn)題中的一種解決方案,而且是不完美的解決方案。我們順著推理去到一個(gè)地方很容易犯的一個(gè)錯(cuò)誤就是認(rèn)為路只有這一條而忽視其他可能性(估計(jì)這也是導(dǎo)致很多爭(zhēng)斗的原因)。另外,我們?cè)谟懻撘患挛锊煌昝赖臅r(shí)候是有一個(gè)情境的,所以請(qǐng)不要像“我說(shuō)它色彩單一,然后你把它涂成彩色后證明我是錯(cuò)的”。
MVC的一般流程是這樣的:View(界面)觸發(fā)事件--》Controller(業(yè)務(wù))處理了業(yè)務(wù),然后觸發(fā)了數(shù)據(jù)更新--》不知道誰(shuí)更新了Model的數(shù)據(jù)--》Model(帶著數(shù)據(jù))回到了View--》View更新數(shù)據(jù)
這里也不多再陳述MVC的原理、實(shí)踐等等,因?yàn)檫@就太長(zhǎng)篇大論了。
?
?
Model-View-Presenter和一些衍生
像我們之前推理的,分化是一種需求的必然結(jié)果,但卻沒(méi)有個(gè)一個(gè)確定的結(jié)果,比如Code Behind和Code Block的問(wèn)題等等。
MVC順著需求把UI相關(guān)的工作分化成了三份,這點(diǎn)經(jīng)過(guò)實(shí)踐證明無(wú)可厚非。但是它們的三角關(guān)系卻被一些人認(rèn)為帶來(lái)了一些問(wèn)題,或者應(yīng)該說(shuō)他們有“更好的”解決方案。
在只有Code Behind和Code Block的那個(gè)時(shí)候維護(hù)是很直接的,不是在同一段代碼內(nèi)解決就是在同一個(gè)關(guān)聯(lián)的事件上解決。三角關(guān)系的問(wèn)題就是維護(hù)問(wèn)題。在MVC,當(dāng)你有變化的時(shí)候你需要同時(shí)維護(hù)三個(gè)對(duì)象和三個(gè)交互,這顯然讓事情復(fù)雜化了。
我們之前說(shuō)到,隨著摩爾定律,軟件的需求不斷地變化和變得龐大。隨著需求變得龐大的時(shí)候,需求變化也變得頻繁,這是一個(gè)出現(xiàn)了無(wú)數(shù)次以后也將會(huì)出現(xiàn)無(wú)數(shù)的無(wú)數(shù)次的一個(gè)問(wèn)題,所以它需要一個(gè)解決方案,哪怕它不一定能被解決。
為了解決需求變化,從《人月神話》到敏捷到DDD,它不是我們已經(jīng)解決了的問(wèn)題,而是我們正在解決的問(wèn)題。放在UI的模式和MVC上來(lái)講,就是優(yōu)化或者替代MVC模式,其中之一就是Model-View-Presenter(MVP)模式。
我們先看看兩個(gè)MVP模式的圖:
(圖一)
(圖二)
兩幅圖是不同的,但是對(duì)MVC的改進(jìn)的思想?yún)s是一樣的:切斷的View和Model的聯(lián)系,讓View只和Presenter(原Controller)交互,減少在需求變化中需要維護(hù)的對(duì)象的數(shù)量。
這種方式很符合我們的期待,因?yàn)槲覀儍A向于:
- 用更低的成本解決問(wèn)題
 - 用更容易理解的方式解決問(wèn)題
 
許多時(shí)候并不是一種模式不好,而是因?yàn)槿藳](méi)辦法執(zhí)行,比如不容易理解,我們就會(huì)選擇容易理解的方式。計(jì)算機(jī)依賴摩爾定律用數(shù)量的增長(zhǎng)來(lái)解決問(wèn)題,而人是用方式的改變來(lái)解決問(wèn)題的。同樣因?yàn)榭陀^原因我們不善于維護(hù)多個(gè)對(duì)象和多個(gè)對(duì)象之間的關(guān)系,所以我們改變了,或者說(shuō)簡(jiǎn)化了這種方式。
MVP定義了Presenter和View之間的接口,讓一些可以根據(jù)已有的接口協(xié)議去各自分別獨(dú)立開(kāi)發(fā),以此去解決界面需求變化頻繁的問(wèn)題。上面兩圖都有接口,不過(guò)接口的實(shí)現(xiàn)和使用細(xì)節(jié)不一樣,不過(guò)思想上是一致的。
在這里要提到的是,事實(shí)上,需求變化最頻繁的并不一定是最接近用戶的界面,但基本可以確定的是,最接近用戶的界面是因?yàn)樾枨笞兓枰铑l繁更改的。當(dāng)然,如果View如果是API而不是UI,那就另說(shuō)了。
還有一些用來(lái)“解決”MVC這項(xiàng)缺點(diǎn)的比如有:ASP.NET MVC的ViewBag,Cocoa的delegate。它們都為了簡(jiǎn)化數(shù)據(jù)更新的問(wèn)題而存在,包括MVVM。
?
?
Model-View-ViewModel
先直接看看Model-View-ViewModel(MVVM)的圖:
?
從圖上看是比MVP簡(jiǎn)單了,更不用說(shuō)MVC了。個(gè)人不認(rèn)為MVVM是從MVP進(jìn)化而來(lái),我只覺(jué)得這是在MVP之后出現(xiàn)的一種“更好的”UI模式解決方案,但是用MVP來(lái)與之對(duì)比比較容易說(shuō)明問(wèn)題。
ViewModel大致上就是MVP的Presenter和MVC的Controller了,而View和ViewModel間沒(méi)有了MVP的界面接口,而是直接交互,用數(shù)據(jù)“綁定”的形式讓數(shù)據(jù)更新的事件不需要開(kāi)發(fā)人員手動(dòng)去編寫(xiě)特殊用例,而是自動(dòng)地雙向同步。數(shù)據(jù)綁定你可以認(rèn)為是Observer模式或者是Publish/Subscribe模式,原理都是為了用一種統(tǒng)一的集中的方式實(shí)現(xiàn)頻繁需要被實(shí)現(xiàn)的數(shù)據(jù)更新問(wèn)題。
比起MVP,MVVM不僅簡(jiǎn)化了業(yè)務(wù)與界面的依賴關(guān)系,還優(yōu)化了數(shù)據(jù)頻繁更新的解決方案,甚至可以說(shuō)提供了一種有效的解決模式。
至此,我們能理解為什么許多人認(rèn)為MVVM是最好的一種模式,沒(méi)有之一。但事實(shí)上,MVVM也是依賴于我們至今所講的“特有的情境”。
當(dāng)然,最優(yōu)雅的也是第一個(gè)能作代表的實(shí)踐就是Windows Presentation Foundation(WPF)了。
?
?
Web
之上,我們?cè)谀J窖葑兊耐普摶旧隙歼€是基于桌面軟件的,但是過(guò)去十年卻是互聯(lián)網(wǎng)的時(shí)代。實(shí)際上大部分讓大家爭(zhēng)議的并不是在桌面領(lǐng)域最合適的是那個(gè),而是在Web領(lǐng)域的模式問(wèn)題,也就是在B/S場(chǎng)景下的問(wèn)題。
當(dāng)軟件離開(kāi)單機(jī),去到網(wǎng)絡(luò)的時(shí)候,因?yàn)閳?chǎng)景變了,所以原有的解決方案也變了,不過(guò)需求依然是不變的。我們依然要解決的問(wèn)題是用戶交互與數(shù)據(jù)更新的問(wèn)題,還有維護(hù)等等的問(wèn)題。
當(dāng)場(chǎng)景變到Web的時(shí)候,我們發(fā)現(xiàn)MVVM用來(lái)做服務(wù)端是極其不適用的,至少現(xiàn)在是不適用的。而MVP你提都不用提。為什么呢?因?yàn)?#xff1a;
- 網(wǎng)絡(luò)資源成本過(guò)高
 - 開(kāi)發(fā)成本過(guò)高
 
問(wèn)大家一個(gè)問(wèn)題,當(dāng)一個(gè)網(wǎng)頁(yè)的數(shù)據(jù)更新后,你希望更新用戶看到的數(shù)據(jù),你會(huì)怎么做?
一般情況下,你會(huì):
window.location.reload();就算你不這么做,用戶也會(huì):
F5?
就像之前說(shuō)的,我們會(huì)選擇更直接的方式解決問(wèn)題。直接刷新頁(yè)面的原因是因?yàn)檫@樣更直接,更容易解決數(shù)據(jù)更新的問(wèn)題。
很多時(shí)候你不會(huì)愿意為了一個(gè)數(shù)據(jù)更新寫(xiě)一個(gè)AJAX,更別說(shuō)這個(gè)AJAX要帶來(lái)Loading、事件順序處理、網(wǎng)絡(luò)問(wèn)題、異常處理等等,這就是開(kāi)發(fā)成本過(guò)高。
另一個(gè)網(wǎng)絡(luò)成本過(guò)高就更容易解釋了,雖然寬帶是基本包月的,但也不帶這么用的,何況還有移動(dòng)用戶。更主要的原因是,在本地軟件,更新數(shù)據(jù)是一個(gè)引用問(wèn)題,而在網(wǎng)絡(luò)應(yīng)用上,這是一個(gè)傳輸問(wèn)題。傳輸成本遠(yuǎn)高于引用成本,引用之上頂多是在本地內(nèi)存中再進(jìn)行一次內(nèi)存拷貝。
這個(gè)時(shí)候,我們會(huì)更傾向于用MVC模式,因?yàn)樵赪eb層面,我們更傾向于一次性更新數(shù)據(jù)。
?
?
Web的MVVM
所有問(wèn)題都不是問(wèn)題,就算有問(wèn)題也要解決問(wèn)題。
為什么這個(gè)標(biāo)題下突然冒出這么一句話?我想說(shuō)的是,需求依舊是不變的,是推動(dòng)進(jìn)步的原動(dòng)力。
還有我之前說(shuō)過(guò),當(dāng)我們討論或者爭(zhēng)論一個(gè)問(wèn)題的時(shí)候,問(wèn)題的對(duì)象已經(jīng)發(fā)生改變了,而且這次是在我們討論這個(gè)問(wèn)題之前已經(jīng)發(fā)生改變了。
網(wǎng)絡(luò)資源成本不斷下降,相信已經(jīng)不需要多提及。摩爾定律和相近的一些原理正在發(fā)揮著它應(yīng)用的作用,網(wǎng)絡(luò)帶寬越來(lái)越高、相應(yīng)速度越來(lái)越快。
如果傳輸因?yàn)橄鄬?duì)成本下降而導(dǎo)致數(shù)據(jù)傳輸?shù)某杀镜陀陂_(kāi)發(fā)人員拒絕客戶的成本,那么它就會(huì)被實(shí)現(xiàn)而不是被拒絕。
另外還有一點(diǎn)就是因?yàn)榧夹g(shù)的進(jìn)步,技術(shù)的資源不斷被更大規(guī)模地壓榨,需求也不斷地增長(zhǎng),那么需求始終會(huì)增長(zhǎng)超過(guò)相對(duì)不變的開(kāi)發(fā)成本的。比如jQuery的出現(xiàn)解決了很多問(wèn)題,我們現(xiàn)在更多地去使用AJAX,哪怕很大一部分依然是為了解決網(wǎng)絡(luò)資源不足的問(wèn)題;我們會(huì)用更多的樣式代碼而用了相對(duì)更少的圖片;我們不再那么依賴Flash一類的矢量圖解決方案而直接錄制視頻。
至少上一節(jié)我們說(shuō)到的兩個(gè)導(dǎo)致大家選用MVC的問(wèn)題都正在被解決,所以我們有理由相信未來(lái)Web不僅僅需要MVC,可能會(huì)需要MVVM或其他解決方案。至少我們能理解容易理解為什么前端會(huì)出現(xiàn)一些MVVM的框架,比如先驅(qū)knockout.js和AngularJs。這些框架本身的好壞就不作討論了,因?yàn)槲覀冇懻摰氖悄J健?/p>
在Web上,MVVM的對(duì)比對(duì)象就不是MVC,而是Code Block。
數(shù)據(jù)即時(shí)更新的需求在擴(kuò)大,但未必有達(dá)到一定要用MVVM這一等級(jí)的高大上的模式,實(shí)際上如果你要更新一個(gè)數(shù)據(jù),你還是會(huì)采取:
$('.notice').html('發(fā)送成功!');因?yàn)?.....我們依然會(huì)采取更直接的方式解決問(wèn)題......
實(shí)際上,現(xiàn)在Web MVVM主要并不是用在了Web或者Wap上,而是移動(dòng)App上。按照前面的說(shuō)法,只可能是:
- HTML+JS比原生在一些場(chǎng)景上更適合Native
 - 在移動(dòng)App上比Web上更適合使用MVVM
 
哪怕是Native開(kāi)發(fā),實(shí)際上iOS的開(kāi)發(fā)上也是用類似的數(shù)據(jù)綁定的方式的。這里也不深究了,畢竟我也不算懂iOS。
要說(shuō)的是,在Web MVVM或者Web的模式上,也就是Web的富應(yīng)用上,現(xiàn)在還不過(guò)是個(gè)初期由膨脹的需求推動(dòng)的階段。重要的不是技術(shù)會(huì)怎么走,而是需求和客觀條件會(huì)怎么走。
可能Webform會(huì)因?yàn)楦咚匍_(kāi)發(fā)而煥發(fā)第二春,它的AJAX的模式也十分滿足于簡(jiǎn)單開(kāi)發(fā),但似乎大家需要的不是GUI式的網(wǎng)頁(yè)。
?
?
結(jié)尾語(yǔ)
我們不一定需要MVVM,但我們一定需要更強(qiáng)大的方式去解決不斷膨脹的Web需求。
我們可以預(yù)見(jiàn)的是:
- 會(huì)有更強(qiáng)大的瀏覽器
 - 會(huì)有更強(qiáng)大的JavaScript或者框架
 - 會(huì)有更加適合的模式
 
除去客氣話的部分,我還是想說(shuō),在不同的需求下其實(shí)有最適合的解決方案,通常讓我們糾結(jié)的不是因?yàn)槟膫€(gè)解決方案更好,而是我們看到的條件不夠多。
編譯語(yǔ)言當(dāng)然比解釋語(yǔ)言效率高,但考慮到開(kāi)發(fā)和維護(hù)成本,JavaScript等始終會(huì)大行其道,比如Node.JS、Python;.NET和微軟當(dāng)然很強(qiáng)大,移植.NET到其他平臺(tái)也很容易,但微軟是家有自己商業(yè)模式和要賺錢(qián)的公司;當(dāng)然有些實(shí)踐和技術(shù)更好,但其他開(kāi)發(fā)人員會(huì)避開(kāi)甚至否定自己不擅長(zhǎng)的東西,大家都喜歡確定的東西;有些技術(shù)更強(qiáng)大,但是只是基于特殊的客觀條件和需求,如果你想做大,要么創(chuàng)造客觀條件,要么把它結(jié)合需求......
總結(jié)
以上是生活随笔為你收集整理的从Script到Code Blocks、Code Behind到MVC、MVP、MVVM的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: 全军出击怎么退战队
 - 下一篇: Basic Calculator