MVC是一種設計模式(Design pattern),也就是一種解決問題的方法和思路, 是上世紀80年代提出的,到如今已經很有歷史了。 MVC的意義在於指導開發者將數據與表現解耦,提升代碼,特別是模型部分代碼的複用性。php
MVC不只僅存在於Web設計中,在桌面程序開發中也是一種常見的方法。MVC的出現已經有一段歷史了。 記得我最先了解到MVC的時候,是在Microsoft的Visual C++ 中的MFC中。 當時年少無知,覺得是MFC中特有的東西。後來隨之不斷學習,才發現本身的天真。 因此說,學得越多,就越以爲本身無知。越以爲本身無知,就越懂得敬畏和謙遜。 從這個角度講,同窗們,最好不要看不起謙遜的人。前端
有個這麼一個段子,說一天A君在圈內聚會時,朋友介紹了另外一我的B君互相認識。 聚會場合嘛,這很正常,也很廣泛。因而AB君小聊了一下。按國人的習慣,A君就問了「先生在哪高就?」。 B君只說了句,「談不上高就,炒炒股。」 「哦,原來是炒股的。」A君心想,雖沒以爲什麼不對,但心理以爲B有點low,只是沒說破,也沒表現出來。 事後了一段時間,一次偶然機會,發現原來B君是國內某上市公司的二股東,身家過億。 人家沒說慌,確實是炒股的……程序員
話說遠了,咱們還說正題。MVC是三個單詞的縮寫:Model, View, Controller。 MVC是一種設計模式,目前幾乎全部的Web開發框架都創建在MVC模式之上。 固然,最近幾年也出現了一些諸如MVP, MVVM之類的新的設計模式。 但從技術的成熟程度和使用的普遍程度來說,MVC還是主流。ajax
Yii是一個Web框架,從Web開發的分工來說,Yii的開發工做中,承擔後端的內容多一些,畢竟主要就是PHP開發。 前端主要是在HTML、JavaScript、CSS上進行開發,而後經過Yii把前端的內容管起來,如經過Assets等。 這一章要講的MVC,主要是針對後端的。 前端的MVC嚴格來說不屬於Yii的範疇,這裏咱們就不做過多介紹。 若是想了解前端的MVC,能夠看看Backbone.js Angular.js等前端框架。數據庫
MVC是模型(Model)、視圖(View)、控制器(Controller)3個單詞的縮寫。 下面咱們從這3個方面來說解MVC中的三個要素。後端
對於MVC中三者的劃分並無十分明晰的定義和界線。MVC設計模式只是一種指導思想, 讓你按照model, view, controller三個方面來描述你的應用,並經過三者的交互,使應用功能得以正常運轉。設計模式
其中,View的部分比較明確,就是負責顯示嘛。一切與顯示界面無關的東西,都不該該出如今View裏面。 所以,View中通常不會出現複雜的判斷語句,不會出現複雜的運算過程。 對於PHP的Web應用而言,毫無疑問,HTML是View中的主要內容。這是關於View的幾個原則:數組
對於Model而言,最主要就是保存事物的信息,表徵事物的行爲和對他能夠進行的操做。 好比,Post類必然有一個用於保存博客文章標題的title屬性,必然有一個刪除的操做,這都是Model的內容。 如下是關於Model的幾個原則:瀏覽器
對於Controller,主要是響應用戶請求,決定使用什麼視圖,須要準備什麼數據用來顯示。 如下是有關Controller的設計原則:前端框架
在MVC中,Model排第一,是有必定暗示的。一是Model是整個架構中,代碼量最大,複用程度最高, 也是最體現程序員設計功力的地方。 二是View和Controller相對於Model而言,在實際開發中,複用程度不高,邏輯複雜程度較低。 能夠說,Model設計得好,整個MVC就好,應用開發起就順。
所以,這一節將以Model爲核心,來說MVC的設計。 實話說,MVC儘管提出了Model View Controller的劃分思想,但到了具體實操中,並非很好把握的。 下面介紹的設計參考,也僅僅是我的在實際項目中的一些體會和想法,僅做參考。 在具體設計中,能夠後把握這麼幾點:
應用當中涉及到的全部業務對象都應儘量抽像成Model。 如,博客系統當中,文章要抽象成Post,評論要抽象成Comment。 而相關的業務邏輯,如發佈新文章能夠用 Post::create() ,刪除評論能夠用 Comment::delete() 。 這樣子整個應用就顯得很清晰明瞭。
在一個應用中,特別是對於大型複雜應用,Model間關係可能比較複雜。在構造應用時,特別是基礎Model時, 要從足夠小的粒度來設計。 此時,就要考慮採起繼承、封裝等措施了。 好比,一個博客文章Post,通常包含了若干標籤,在頁上通常寫在做者、日期等Post字段的旁邊。 從邏輯上來看,把標籤做爲Post的一個屬性,是說得通的。 可是若是把標籤做爲一個屬性像標題、正文等字段同樣依附於Post。那麼在有的功能上,實現起來是有難度的。 好比,客戶要求,當一個Post含有標籤 「yii, model」 時,能夠點擊 「yii」 , 而後系統列出全部具標籤中含有 「yii」 的文章。
爲了實現這個功能,正確的設計是單獨將標籤抽象成Tag。這樣,Post和Tag是多對多的關係, 即一個Post有多個Tag,一個Tag也對應多個Post。這個多對多關係能夠經過一張數據表 tbl_post_tag 來表示。 接下來,爲Post增長 Post::getTags() 方法,並經過 tbl_post_tag 表來查詢當前Post的全部標籤。 同時,爲Tag增長 Tag::getPosts() 方法,也經過 tbl_post_tag 表來查詢當前Tag對應的文章。 這樣,就具有了實現客戶要求的新功能的基礎。
所以,在Model設計上,要以儘可能小的粒度進行設計。通常而言,粒度越小,複用的可能性就越高。
有的讀者可能會問了,既然要求粒度儘量地小,那麼,Post是否是也應當再細化,把段落抽象爲Model? 是否有這個必要,看客戶需求。通常狀況確實沒有這必要,若是這麼作,那是否是再以句子爲單位進行抽象? 但若是客戶要求這個博客系統的評論是針對段落進行的評論的, 要將評論顯示在對應的段落旁邊,甚至顯示每一個段落評論人次等功能。那麼就須要把段落抽象成Model了。
從設計流程上,數據庫結構設計與Model的設計是緊密相關的。先有數據庫結構設計,後有Model設計。 在設計數據庫結構的時候,也是在設計Model。 通常而言,最單元、粒度最小的Model就是根據每一個數據庫表所生成的Model,這每每是個Active Record。
好比標籤的問題,在數據庫存儲過程當中,Post和Tag是分開存的,並且這兩個表的字段,沒有冗餘。 tbl_post_tag 表也只記錄他們的ID,沒有實質內容。
在獲取數據渲染視圖,向用戶展示時,這兩個Model及他們的字段,是徹底夠用,且沒有冗餘的。
那麼,能不能說 Post 和 Tag 這兩個Model是夠用的呢?顯然還不夠。
當用戶在建立文章、修改文章、審覈文章時,須要採用一個表單來顯示來收集用戶輸入。 其中,對於標籤的採集,通常是一個長條的文本框,讓用戶一次性輸入多個標籤,並以 , 等進行分隔的。
可是,這個文本框沒有一個字段與之進行對應。咱們也沒辦法對這個字段的用戶輸入進行任何的驗證、預處理。
所以,Post的功能是不夠用的。不夠用怎麼辦?那就加吧。但直接在 Post 裏面加個 public $tagString 並很差。 畢竟只是在使用表單時,纔會有這個問題,其餘場合,這個字段是沒用的。
這種狀況下,通常使用繼承:
1 2 3 4 5 6 |
public class PostForm extends Post { public $tagString; ... ... }
|
這樣,當控制器發現用戶在建立、修改、審覈文章時,可使用 PostForm Model來渲染視圖了, 而其餘場合則仍使用Post。這樣就在須要時,增長了一個 tagString 的字段用於收集用戶輸入的標籤。
在具體設計過程當中,因爲Model自己就會包含不少代碼,所以,要多使用這繼承等手段,把代碼組織好。
因爲Model的代碼量比較大,又集中了大量的邏輯,所以,會在一個Model中有大量的方法。仍然以Post爲例, 會涉及到建立、審覈、發佈、回收等流程,相關的方法比較多,在命名上要用心。 可能會涉及到的、名字又比較接近的方法就有:
這裏只是一些獲取其餘Post的方法,命名比較合理,一看就知道意思。 並且所有寫成getter的形式,可使用讀取屬性的方式進行訪問。
不僅僅是在Model方法的命名上要用心, 在變量名、類名、方法名等的命名上,也要養成習慣,造成規律。 不要圖一時之快,胡亂起名。不然,出來混,早晚要還的。
從MVC的起源來說,是從桌面應用的開發中發展起來的。從本質來說,這是一種解決問題的思路和辦法。 從實踐來說,這是一種久經考驗的有效方式。可是如開頭咱們講的,Yii更多的是側重於後端。 對於Web應用而言,包含Yii在內的許多Web開發框架,都是沒有辦法知道用戶的操做,如鼠標、鍵盤等操做的。 Web應用想要了解用戶的操做,只能依靠用戶發送Request。 而對於鼠標、鍵盤等的響應,只能依靠前端技術,如JavaScript等來實現。
再加上這幾年來Web瀏覽器的功能日臻強大。所以,Web應用開發出現了一個新的發展苗頭,就是功能從後端往前端轉移。
在前端,經過JavaScript捕獲用戶操做,進行相應處理。 或是發送回後端獲取響應後處理,如經過ajax請求後端數據,實現無刷新的局部頁面更新,向用戶進行反饋; 或直接在前端由瀏覽器進行處理,如使用backbone.js、Angular.js等前端框架的數據綁定功能等。 這些都使得Web應用表現得愈來愈像桌面應用。
後端MVC也在爲先後端的發展而改變。 Controller的功能更多的變成了識別是ajax請求仍是普通請求, 並根據請求的不一樣採起相應的視圖渲染方式。對於普通請求,正常渲染視圖,輸出HTML。 對於ajax請求,則返回局部渲染視圖,輸出HTML片斷。有的甚至輸出XML或者JSON。 惟一在大潮流中,巍然不動的,仍是咱們的大Model。