很早就知道有這三個概念,但是一直都不清楚是怎麽回事,在網上搜索,都是泛泛而談,沒有具體例子,新手是看不懂的,直到找到這篇文章,我對這三個架構有了更清楚的了解。
從一個簡單的例子去研究這三個架構。
註意,MVC,MVP,MVVM中的C,P,VM,下文都要controller指代。
需求如下
界面上顯示100,以及兩個按鈕,其中一個點一下加1,另外一個點一下減1
如圖
誠然,這麽簡單的需求,並不需要用什麽架構去完成,可是如果是復雜的需求,要長篇大論才能說完,所以只拿簡單的來做例子,實際開發中,你在完成一個需求之前,是需要好好掂量是否要用架構,要的話,用什麽架構(不局限於這三個),架構裏面又要用什麽設計模式等等。經過我的實踐,發現,即使是架構改變了,view是可以完全不變的,所以先展現view層的代碼。
html部分
<span id="text">100</span> <button id="upBtn">up</button> <button id="downBtn">down</button>
js部分
function $(id) { return document.querySelector(`#${id}`); } function View(controller) { const upBtn = $('upBtn'); const downBtn = $('downBtn'); const textSpan = $('text'); this.render = function(model) { textSpan.innerHTML = model.getValue(); } upBtn.onclick = controller.up; downBtn.onclick = controller.down; }
render方法是核心,方法名稱不能改(後面要依賴這個render方法),其中要實現數據的展示邏輯,然後是一些點擊事件的綁定
MVC
model層
function Model() { let value = 100; this.up = function() { value += 1; }; this.down = function() { value -= 1; }; this.getValue = http://www.cnblogs.com/maoscut/p/function() { return value; }; }
保存數據,並提供訪問,修改數據的方法,如果僅僅是這樣,那麽當model改變時,view是不知道的,所以需要讓model去通知view,我數據改變了,你要更新了。怎麽做呢?利用觀察者模式。在model中,增加一個數組views,去保存這個model對應的視圖,在修改數據的時候,遍歷views數組,調用每個view的render方法,參數是自己。
修改後的model
function Model() { let value = 100; const self = this; const views = []; this.up = function() { value += 1; }; this.down = function() { value -= 1; }; this.getValue = http://www.cnblogs.com/maoscut/p/function() { return value; }; this.broadcast = function() { views.forEach(view => view.render(self)); }; this.subscribe = function(cb) { views.push(cb); } }
仔細看修改後的model,雖然增加了通知的方法(broadcast),但是在修改數據的方法(up和down)中並沒有去通知視圖。這個工作是由controller承擔的,另外把view註冊到model中,也是controller做的。
controller層
function Controller() { let view = null; let model = null; this.up = function() { // 修改數據 model.up(); // 通知視圖 model.broadcast(); }; this.down = function() { model.down(); model.broadcast(); } this.init = function() { view = new View(this); model = new Model(); // 把視圖註冊到model中 model.subscribe(view); } }
可以看到,controller把自己傳給了view去創建視圖,同時保存引用,創建model後,把view註冊到model中。同時實現了,改變數據,通知視圖的工作。
請一定要好好理解MVC,後面的MVP,MVVM都只是稍加修改而已。
MVP
在MVC中,改變數據,通知視圖,都是在controller做的,註冊視圖,以及通知視圖,這兩個方法的實現,都是model完成的,既然model負責數據處理,這兩個工作實際上和改變數據是沒關系的,把他們都轉移到controller中,不僅可以讓model層專註於數據處理,同時也方便多個視圖共用一個controller
model層
function Model() { let value = 100; this.up = function() { value += 1; }; this.down = function() { value -= 1; }; this.getValue = http://www.cnblogs.com/maoscut/p/function() { return value; }; }
model層更小了,刪除了註冊,通知方法,只保存數據和提供獲取,修改數據的方法
controller層
function Controller() { let views = []; let model = null; function broadcast() { views.forEach(view => view.render(model)); } this.up = function() { model.up(); broadcast(); }; this.down = function() { model.down(); broadcast(); } this.init = function() { views.push(new View(this)); model = new Model(); } }
controller,增加了廣播方法,該方法的實現和調用都在controller中,另外,如果想多個視圖共用一個controller,如果這多個視圖都是同一個model,上面代碼能夠勝任,如果是這多個視圖是不同的model,那就要自己去實現好view和model的對應關系了(要用map來存儲對應關系,一個數組做不到)。
MVVM
可以看到,在MVP中,model也有一個up方法,controller也有一個up方法,只是增加了一個廣播方法的調用。是不是有些重復呢?把這兩個類似的方法整合到controller,model只負責保存數據,不實現修改數據的邏輯,這就是MVVM了,極大地精簡model
model層
function Model() { let value = 100; this.getValue = http://www.cnblogs.com/maoscut/p/function() { return value; }; this.setValue = http://www.cnblogs.com/maoscut/p/function(v) { value = v; } }
其實,不用函數,單純地用一個變量,也是可以的,但是為了view層不變,view層中依賴model的getValue方法,所以這裏還是用函數去實現model
controller層
function Controller() { let views = []; let model = null; function broadcast() { views.forEach(view => view.render(model)); } this.up = function() { model.setValue(model.getValue() + 1); broadcast(); }; this.down = function() { model.setValue(model.getValue() - 1); broadcast(); } this.init = function() { views.push(new View(this)); model = new Model(); } }
精簡model的代價是controller要做更多的事情,實現修改數據的邏輯,通知視圖。如果用框架,react或者vue,通知視圖這部分框架會幫你實現,只要實現數據修改的邏輯就好了。
至此,三個架構都講完了,如果錯誤,歡迎討論。
代碼可在github上下載,需要node環境。
參考資料:http://www.cnblogs.com/zhouyangla/p/6936455.html
Tags: 架構 controller quot function 三個 需求
文章來源: