幾乎全部應用系統都是由這三部分組成:表示企業數據和業務規則的數據,用來展現數據的,用戶看到並與之交互的界面,負責轉發請求,對請求的處理;協調數據和展現的邏輯。在MVC出現以前,這三部分都是寫在一塊兒的,是耦合的,這對軟件工程是很差的。設計模式
1979年,Trygve Reenskaug在Smalltalk-80系統上首次提出了MVC的概念,最初的時候叫作Model-View-Controller-Editor。1994年,Gof(Gang of Four)在 Design Patterns: Elements of Reusable Object-Oriented Software 一書中對MVC模式作了深刻的解析。架構
Trygve Reenskaug最初提出MVC的目的是爲了把數據(Model
)和視圖(View
)分離開來,而後用控制器(Controller
)做膠水來粘合M和V之間的關係。很顯然,這樣作的目的是爲了實現注意點分離這樣一個更高層次的設計理念,View
就只負責視圖相關的東西,Model
就只負責描述數據模型,Controller
負責總控,各自協做。app
經過把職責、性質相近的成分歸結在一塊兒,不相近的進行隔離,MVC將系統分解爲模型、視圖、控制器三部分,每一部分都相對獨立,職責單一,在實現過程當中能夠專一於自身的核心邏輯。MVC是對系統複雜性的一種合理的梳理與切分。框架
Model對view和controller均可知,view對controller可知,controller對誰都不可知。ide
這裏爲了容易理解,我想用咱們實驗室三個屋來打個比方,小屋是view,中屋是controller,大屋是model。函數
用戶請求、試圖選擇:小屋不認識中屋,可是中屋認識小屋,小屋一旦有需求,中屋就會默默地知足他的要求,好比:小屋的賈老師大喊一聲「把三木球拉出去」,中屋就來了一我的把三木球拉了出去。this
狀態查詢:小屋認識大屋,小屋想知道大屋的郭師兄今天穿了件什麼顏色的衣服,就跑去看了看,哦,原來郭師兄穿了件綠色的衣服。編碼
用戶請求、狀態改變、通知改變:賈老師大喊一聲「給郭師兄換件紅色的衣服」,隔壁屋的一我的就去給他換了,郭師兄換完衣服,開心地大喊了一句「我換了件紅色的衣服!」。spa
其實這裏,我對狀態的理解仍是有些模糊,暫且把它當作數據,好比登陸,某種角色的用戶登陸後,controller會告訴model改變狀態,而後通知給view,也就是展現給該角色的用戶相應的數據。設計
GoF (Gang of Four,四人組, 《Design Patterns: Elements of Reusable Object-Oriented Software》/《設計模式》一書的做者:Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides)並無把MVC說起爲一種設計模式,而是把它當作"一組用於構建用戶界面的類集合"。在他們看來,它實際上是其它兩個個經典的設計模式的演變:觀察者模式(Observer)(Pub/Sub)和策略模式(Strategy)。
正如咱們所討論的,models表示應用的數據,而views處理屏幕上展示給用戶的內容。爲此,MVC在覈心通信上基於推送/訂閱模型。
view: models[0...n]; callbackModelEvents[0...n]; for(model 0...n) for(model[i].Event(0...n)) this.on(Events[j], callbackModelEvent[k]);
View(訂閱者)註冊了一組model和model對應的事件的處理函數,當model(發佈者)一旦發佈了消息,view就會接收。
View和controller同上。
Extjs這個框架是典型的MVC模式,它幫咱們完成了MVC的大部分工做,爲了體現MVC模式,提供給咱們這樣的接口,固然,咱們用戶的主要代碼就是寫在這裏的。
這是ExtJs4.2的工程文件目錄,咱們的代碼就寫在controller、model、store、view這四個文件夾下,接下來,咱們看一下Ext代碼是怎麼寫的。
Ext.define("Srims.view.patent.PatentList", { extend: 'Ext.grid.Panel', store: [patent.patents], …… });
在view中,咱們能夠配置當前view對應的store(即數據),當數據更新時,從model發出消息,展現在view中,固然,咱們須要配置這麼一行代碼,剩下的框架已經幫咱們作好了。
Ext. define('Srims.controller.patent.patentList', { extend: 'Ext.app.Controller', views: ['patent.patentList'], model:[patent.patents], …… 'patentlist button[itemId=btnDeletePatent]': { //刪除按鈕點擊響應 click: function (button, e) { Ext.MessageBox.confirm('確認', '確認刪除選中記錄麼?', function (btn) { if (btn == 'yes') { var panel = button.up('panel'); var selectionRecord = panel.getSelectionModel().getSelection()[0]; var store = panel.getStore(); store.remove(selectionRecord); } }, this); …… } }, …… });
在controller中,能夠配置當前controller對應的view、model,在方法中也能夠對view對應的store操做,也能夠直接建立store(model)的實例,對其操做。
經過這樣配置,能夠實現觀察者模式。
在Ext中,view和controller是多對多的關係,好比,controller對它註冊的多個view進行消息響應或者操做,假如要選擇view1通常經過get方法,就是get加view1做爲方法名,使用的,這樣看上去是沒問題的。
可是Ext是基於類的,實際應用中,咱們一般是這樣的,因爲不少view長得很像甚至相同,咱們習慣複用同一個view類,這樣,一個view類對應着多個實例。咱們在controller中的全部方法都是針對他對應的view類的,當咱們建立了一個controller實例,經過該類中的方法找到對應的view類,來操做這個view類對應的view實例,這時候,一個view對應着多個實例,操做就會產生混亂。
固然,只要咱們在編碼是注意經過controller中適當處理邏輯,在view中適當添加標誌位,混亂和衝突也是能夠解決的。因此從此,適當複用而且提升編碼能力,也是沒問題的。
在傳統的MVC架構裏包括Extjs,一個controller可能有多個方法,每一個方法每每對應一個user action,所以,一個controller每每對應多個user action。傳統MVC架構裏將一個user action委派到某個controller的某個方法的過程。
目前,不少平臺的主流MVC框架在設計上都引入了command模式,command模式的引入改變了傳統MVC框架的結構,受衝擊最大的就是 controller。
在基於command的MVC架構裏,一個command每每只對應一個user action,在該架構裏變成了將useraction與command一一綁定的過程。
主流MVC框架向command轉型一個很是重要的緣由就是:因爲缺乏合理的組織依據,controller的粒度很難拿捏。
controller不一樣於view與model,view與model都有各自自然的粒度組織依據,view的組織粒度直接承襲用戶界面設計,model的組織粒度則是依據某種分析設計思想(如OOA/D)進行領域建模的結果,controller須要同時協調view與model,可是view與model的組織結構和粒度都是不對等的,這就使得controller面臨一個"在多大視圖範圍內溝通與協調多少領域對象"的問題,因爲找不出合理的組織依據,設計者在設計controller時每每感到無所適從。
Extjs雖然在這方面考慮欠佳,但咱們能作的就是遵循良好的設計原則,對某些較"大"的user action方法進行分解,從中抽離出一些可複用的部分封裝成一些較"小"的方法,儘可能減少代碼的冗餘。