2.Rails應(yīng)用程序的架構(gòu)
Rail的有趣點(diǎn)之一是它對(duì)你的web應(yīng)用程序架構(gòu)實(shí)施了一些強(qiáng)制性規(guī)定。令人驚訝的是,這些規(guī)定反而能讓你很容易地創(chuàng)建應(yīng)用程序-非常地容易。讓我們看看為什么?
2.1模型,視圖和控制器
追溯至1979年,Trygve Reenskaug 提出一種開(kāi)發(fā)交付式應(yīng)用程序的新架構(gòu)。在他的設(shè)計(jì)中,應(yīng)用程序被分為三種類(lèi)型的組件:模型,視圖和控制器。
模型負(fù)責(zé)維護(hù)應(yīng)用程序的狀態(tài)。有時(shí)候這種狀態(tài)的持續(xù)時(shí)間是短暫的,僅存在與用戶(hù)的交互過(guò)程中。但有時(shí)候這狀態(tài)又是持久的,它存儲(chǔ)在應(yīng)用程序之外,經(jīng)常是在數(shù)據(jù)庫(kù)。
一個(gè)模型通常不只是數(shù)據(jù);它還執(zhí)行了應(yīng)用在數(shù)據(jù)上的規(guī)則。例如,若規(guī)定少于$20的訂單不予折扣,則模型將實(shí)行此規(guī)則。這是很有意義的。在模型中貫徹這些業(yè)務(wù)規(guī)則,我們能確保在應(yīng)用程序中數(shù)據(jù)的有效性。 因而模型扮演著數(shù)據(jù)檢查及其數(shù)據(jù)存儲(chǔ)雙重角色。
視圖負(fù)責(zé)產(chǎn)生一個(gè)用戶(hù)界面,其通常是基于模型數(shù)據(jù)。例如,一個(gè)網(wǎng)上商店在分類(lèi)中顯示一列商品。這些列表通過(guò)模型被訪(fǎng)問(wèn),但它是作為一個(gè)視圖(此視圖從模型中讀取列表)展示在終端用戶(hù)面前。雖然根據(jù)不同的輸入數(shù)據(jù)可以在用戶(hù)面前展示不同的視圖,但視圖本身無(wú)法改變這些數(shù)據(jù),它要做的唯一工作就是顯示數(shù)據(jù)。為了達(dá)到不同目的,多個(gè)視圖也可能存取同一個(gè)模型數(shù)據(jù)。對(duì)在線(xiàn)書(shū)店,在分類(lèi)頁(yè)面有個(gè)視圖用于顯示產(chǎn)品信息,同時(shí)也有若干視圖供管理員新增和編輯產(chǎn)品。
控制器從外部世界接收事件(通常是用戶(hù)的輸入),和模型進(jìn)行交互,并給用戶(hù)顯示適當(dāng)?shù)囊晥D。
這三種,模型,視圖,和控制器――形成了大家熟悉的MVC架構(gòu)。
MVC最初來(lái)源于傳統(tǒng)的GUI應(yīng)用程序,在那里開(kāi)發(fā)人員發(fā)現(xiàn)分離關(guān)注點(diǎn)可以減少耦合,而這反之又可以使代碼變得容易編寫(xiě)和維護(hù)。每個(gè)概念和動(dòng)作將在一個(gè)眾所周知的位置被表達(dá)。使用MVC就象建造已搭好鋼架的摩天大樓――只需進(jìn)一步填充剩余零件。
在軟件開(kāi)發(fā)世界中,我們經(jīng)常在往前趕路時(shí)忽視了過(guò)去好的想法。當(dāng)開(kāi)發(fā)者第一次開(kāi)始建造web應(yīng)用程序,他們退回到寫(xiě)集成電路程序了,在一個(gè)大的代碼塊中混雜著展現(xiàn),數(shù)據(jù)存儲(chǔ),業(yè)務(wù)邏輯,和事件處理。但是想法慢慢又回到了原來(lái)上了,人們開(kāi)始把已經(jīng)存在了20幾年的MVC思想應(yīng)用在web應(yīng)用程序的架構(gòu)上。這樣的結(jié)果就出現(xiàn)了WebObject,struts和Java Server Faces 等框架。所有的這些都是基于MVC的思想上的。
Ruby on Rails也是一個(gè)MVC框架。Rails強(qiáng)調(diào)應(yīng)用程序的模型,視圖和控制器之間的分離――在應(yīng)用程序執(zhí)行的時(shí)候把它們組織在一起。關(guān)于Rails有趣的是它把這些組織在一起是基于智能的默認(rèn)設(shè)置而不需要你編寫(xiě)任何的外部配置文件。這就是Rails哲學(xué)的一個(gè)例子,約定俗成優(yōu)于配置。
在一個(gè)Rails應(yīng)用程序中,接收到的請(qǐng)求首先被發(fā)送到一個(gè)路由器上,它用于決定在此應(yīng)用程序中,請(qǐng)求將發(fā)送至哪里,及如何解析請(qǐng)求本身。最終,這個(gè)過(guò)程在控制器代碼中決定了一種相應(yīng)方法(在Rails中通常稱(chēng)為“動(dòng)作”)。動(dòng)作將根據(jù)請(qǐng)求查找數(shù)據(jù),它可以和模型進(jìn)行交互,并且它也可能導(dǎo)致其它的動(dòng)作被執(zhí)行。最后這個(gè)動(dòng)作給視圖準(zhǔn)備了信息,呈遞給用戶(hù)。
在下一頁(yè)的圖2.2上顯示了Rails是如何接收一個(gè)請(qǐng)求的。在這個(gè)例子中,假設(shè)在分類(lèi)中顯示產(chǎn)品,用戶(hù)剛剛點(diǎn)擊了其中一個(gè)產(chǎn)品的“Add To Cart”按鈕。這個(gè)按鈕返回了一個(gè)http://my.url/store/add_to_cart/123鏈接給我們的應(yīng)用程序,123是我們選擇的產(chǎn)品的內(nèi)部編號(hào)。
路由器組件接收了請(qǐng)求并把它分為若干部分。在這個(gè)簡(jiǎn)單的例子中,路徑(指的是/store/add_to_cart/123)的第一部分store作為控制器的名稱(chēng),第二部分add_to_cart作為動(dòng)作的名稱(chēng),最后部分123,約定俗成為內(nèi)部變量稱(chēng)為編號(hào)。根據(jù)分析的結(jié)果,路由器在控制類(lèi)StoreController中調(diào)用了add_to_cart方法。
add_to_cart()執(zhí)行了用戶(hù)的請(qǐng)求。從而它查找到了當(dāng)前用戶(hù)的購(gòu)物車(chē),并要求模型查找產(chǎn)品編號(hào)為123的信息,最終把產(chǎn)品添進(jìn)購(gòu)物車(chē)。
現(xiàn)在購(gòu)物車(chē)?yán)锒嗔藗€(gè)新產(chǎn)品,我們要把它顯示給用戶(hù)看。控制器安排視圖從模型中取得了購(gòu)物車(chē)的對(duì)象,并且調(diào)用視圖代碼。在Rails中,這個(gè)調(diào)用通常是隱含的。再次依據(jù)約定把視圖和已知?jiǎng)幼鬟B接起來(lái)。
以上所述就是一個(gè)MVC web應(yīng)用程序。通過(guò)一些約定以及功能性的適當(dāng)分割,你將發(fā)現(xiàn)你的代碼更易于操作,你的程序更易于擴(kuò)展和維護(hù)。這看起來(lái)是一個(gè)良好開(kāi)端。
如果MVC僅僅涉及如何通過(guò)一特定途徑分割你的代碼這個(gè)問(wèn)題,你可能會(huì)質(zhì)疑為什么還需要象Ruby on Rails這樣的框架。答案很簡(jiǎn)單,Rails為你處理所有低級(jí)別的事務(wù),包括所有冗長(zhǎng)細(xì)節(jié),使你能集中精力關(guān)注應(yīng)用程序的核心功能。