模型視圖控制器(MVC)一個至關實用且十分流行的設計模式。做爲一位稱職碼農,你不可能沒據說過吧。 不幸的是它難以讓人理解。 在本文中,我將給出我認爲是MVC的最簡單的解釋,以及爲何你應該使用它。redis
在一個典型應用中,你會發現這三個基本組成部分:設計模式
MVC模式,簡言之,就是:工具
模型表明數據,除此以外別無它用。 模型不依賴於控制器或視圖。佈局
視圖顯示模型數據,發送用戶動做(例如按鈕點擊)到控制器。 視圖能夠:this
獨立於模型和控制器的; 或者spa
做爲控制器,所以依賴於模型。翻譯
控制器提供模型數據至視圖,解釋用戶的行爲,如按鈕的點擊。 控制器依賴於視圖和模型。 在一些狀況下,控制器和視圖能夠合二爲一。設計
規則1是MVC的黃金法則,我再重複一遍:code
模型表明數據,除此以外別無它用。 模型不依賴於控制器或視圖。對象
以一個地址簿應用程序爲例。 模型是一些Person
對象,視圖是一個GUI窗口,顯示聯繫人列表,而且控制器處理用戶行爲諸如「刪除聯繫人」,「添加聯繫人」,「發郵件至聯繫人」等。下面的例子沒有使用MVC,由於模型依賴於視圖。
//Example 1: void Person::setPicture(Picture pict){ m_picture = pict; //set the member variable m_listView->reloadData(); //update the view }
下面的示例使用了MVC:
//Example 2: void Person::setPicture(Picture pict){ m_picture = pict; //set the member variable } void PersonListController::changePictureAtIndex(Picture newPict, int personIndex){ m_personList[personIndex].setPicture(newPict); //modify the model m_listView->reloadData(); //update the view }
在上面的例子中, Person
類並不知道視圖的存在。 PersonListController
負責模型修改和視圖更新。視圖窗口告訴控制器用戶的行爲(就上述狀況而言,它將提醒控制器用戶修改了一個聯繫人的照片)。
沒必要要的複雜性是軟件開發的夢魘。 它致使軟件漏洞百出,維護費用昂貴。而處處引入依賴很容易就會形成代碼過於複雜。 相反地,若是咱們移除沒必要要的依賴能夠改善代碼質量,維護上更容易,由於代碼可重複使用而無需修改。 你能夠安心地複用舊的、穩定的代碼不用顧慮招致新的bug。
MVC設計模式的主要優勢是:
MVC使得模型類不加修改便可重複使用。
控制器存在的目的是消除模型與視圖依賴關係。 從模型中移除視圖依賴後,模型代碼變得整潔起來。
爲何模型代碼能這麼小清新? 讓咱們繼續以地址簿應用爲例。 項目經理找到碼農們,對他們說 」我很欣賞聯繫人列表窗口,但咱們須要另外一個窗口顯示全部聯繫人的照片,這些照片應該是處於一個表格佈局中,每排五張照片。」
若是應用程序採用了MVC,這個任務至關簡單。 目前主要有三個類: Person
, PersonListController
和PersonListView
。 還須要建立兩個類: PersonPhotoGridView
和PersonPhotoGridController
。 在Person
類保持不變的狀況下,很容易插入兩種不一樣的視圖。 怎麼樣啊!
若是應用程序具備例1中相似的結構,任務立馬變得棘手了。此時有兩個類Person
和PersonListView
。Person
類不能插入另外一種視圖,由於它包含了涉及PersonListView類的具體代碼 。 開發人員必須修改Person
類以適應新的PersonPhotoGridView
,並最終像這樣複雜化模型:
//Example 3: void Person::setPicture(Picture pict){ m_picture = pict; //set the member variable if(m_listView){ //check if it's in a list view m_listView->reloadData(); //update the list view } if(m_gridView){ //check if it's in a grid view m_gridView->reloadData(); //update the grid view } }
如你所觀察到的同樣,模型代碼開始變得苦澀。 若是項目經理接着發話:「咱們正在移植的應用程序到一個使用不一樣的GUI庫的平臺」,簡潔性此時尤其突出。 採用MVC的Person
類能夠經過不一樣的GUI工具包顯示無需任何修改。 單單建立一個控制器,並用新的庫中的視圖,就像你用舊的庫同樣。 若是沒有MVC,支持多種GUI工具包將是一場噩夢。 最終代碼可能會這樣的:
//Example 4: void Person::setPicture(Picture pict){ m_picture = pict; #ifdef ORIGINAL_GUI_TOOLKIT if(m_listView){ //check if it's in a list view m_listView->reloadData(); //update the list view } if(m_gridView){ //check if it's in a grid view m_gridView->reloadData(); //update the grid view } #endif #ifdef NEW_GUI_TOOLKIT if(m_listView){ //check if it's in a list view m_listView->redisplayData(); //update the list view } if(m_gridView){ //check if it's in a grid view m_gridView->redisplayData(); //update the grid view } #endif }
setPicture
方法基本上會亂上一團。
一直解決例4中的尷尬代碼的方案是將控制器代碼從模型移動到視圖,像這樣:
//Example 5: PersonListView::newPictureClicked(Picture clickedPicture){ m_selectedPerson.setPicture(clickedPicture); this->reloadData(); }
上述例子也可以使模型易於複用,這是MVC的主要優點。 當視圖將只顯示一種類型的模型對象,合併視圖和控制器是比較合適的。 例如,一個SinglePersonView
將只顯示一個Person
的對象,因此SinglePersonView
可兼做控制器。
然而,若是控制器與視圖分離,MVC有第二個優勢:
MVC可使視圖可重複使用的而無需修改。
MVC模型不只使得模型簡潔,視圖一樣如此。 理想狀況下,列表視圖應該可以顯示的任何列表,不僅是Person
的對象。 例5中的代碼不能是一個通用的列表視圖,由於它與模型耦合在一塊兒(Person
類)。要想視圖(如列表視圖,或表格視圖)和模型代碼同時可重複使用,MVC是惟一的選擇。 控制器移除模型和視圖間的依賴關係,這使得它們在其餘地方能夠被複用。
MVC設計模式在視圖和模型間插入控制器類,移除視圖和模型間的依賴。 模型以及視圖,可重複使用而無需修改。 這樣,實現新的功能和維護變得垂手可得。 該用戶很快獲得穩定的軟件,該公司節省了資金,並且開發人員不發瘋。 這樣好不?
翻譯來源:http://www.tomdalling.com/blog/software-design/model-view-controller-explained/