# MVP
模型-視圖-展示器(MVP)是MVC設計模式的一個衍生模式,它專注于提升展現邏輯.它來自于上個世紀九十年代早期的一個叫做Taligent的公司,當時他們正工作于一個基于C++ CommonPoint環境的模型.而MVC和MVP的目標都直指對整個多組件關注點的分離,它們之間有一些基礎上的不同。
為了要做出總結的目的,我們將專注于最適合于基于Web架構的MVP版本。
## 模型,視圖&展示器
MVP中的P代表展示器.它是一個包含視圖的用戶界面邏輯的組件.不像MVC,來自視圖的調用被委派給了展示器,它是從視圖中解耦出來的,并且轉而通過一個接口來同它進行對話.這允許所有類型的有用的東西,比如在單元測試中模擬視圖的調用。
對MVP最通常的實現是使用一個被動視圖(Passive View 一種對所有動機和目的保持靜默的視圖),包含很少甚至與沒有任何邏輯.如果MVC和MVP是不同的,那是因為其C和P干了不同的事情.在MVP中,P觀察著模型并且當模型發生改變的時候對視圖進行更新.P切實的將模型綁定到了視圖,這一責任在MVC中被控制器提前持有了。
通過視圖發送請求,展示者執行所有和用戶請求相關的工作,并且把數據返回給視圖。從這個方面來講,它們獲取數據,操作數據,然后決定數據如何在視圖上面展示。在一些實現當中,展示者同時和一個服務層交互,用于持久化數據(模型)。模型可以觸發事件,但是是由展示者扮演這個角色,用于訂閱這些事件,從而來更新視圖。在這個被動體系架構下,我們沒有直接數據綁定的概念。視圖暴露setter ,而展示者使用這些setter 來設置數據。
相較于MVC模式的這個改變所帶來的好處是,增強了我們應用的可測試性,并且提供了一個更加干凈的視圖和模型之間的隔離。但是在這個模式里面伴隨著缺乏數據綁定支持的缺陷,這就意味著必須對這個任務做另外的處理。
盡管被動視圖實現起來普遍都是為視圖和實現一個接口,但在它之上還是有差異的,包括可以更多的把視圖從展示器解耦的事件的使用。由于在Javascript中我們并沒有接口的構造,我們這里更多的是使用一種約定而不是一個明確的接口。技術上看它仍然是一個接口,而從那個角度對于我們而言把它作為一個接口引用可能更加說得過去一些。
也有一種叫做監督控制器的MVP的變種,它更加接近于MVC和MVVM模式,因為它提供了來自于直接來源于視圖的模型的數據綁定。鍵值觀察(KVO)插件(比如Derick Bailey的Backbone.ModelBingding插件)趨向于吧Backbone帶出被動視圖的范疇,而更多的帶入監督控制器和MVVM變異中。
## MVP還是MVC?
MVP一般最常使用在企業級應用程序中,這樣的程序中有必要對展現邏輯盡可能的重用。帶有非常復雜的邏輯和大量用戶交互的應用程序中,我們也許會發現MVC相對來說并不怎么滿足需求,因為要解決這個問題可能意味著對多重控制器的重度依賴。在MVP中,所有這些復雜的邏輯能夠被封裝到一個展示器中,它可以顯著的簡化維護工作量。
由于MVP的視圖是通過一個接口來被定義的,而這個接口在技術上唯一的要點只是系統和視圖(展示器除外)之間接觸,這一模式也允許開發者不需要等待設計師為應用程序制作出布局和圖形,就可以開始編寫展現邏輯。
根據其實現,MVP也許MVC更加容易進行自動的單元測試。為此常常被提及的理由是展示器可以被當做用戶接口的完全模擬來使用,而因此它能夠獨立于其它組件接受單元測試。在我的經驗中這取決于我們正在實現的MVP所使用的語言(超過一種取代Javascript來實現MVP的可選語言,同Javascript有著相當大的不同,比如說ASP.net)。
在一天的終點,我們對MVC可能會有的底層關注,可能將是保持對MVP的認可,因為它們之間的不同主要是在語義上的。一旦我們對清晰分離的關注被納入到模型、視圖和控制器(或者展示器)中,我們也許會獲得大部分同樣的好處,而不用去管我們所作出的選擇的差異。
## MVC, MVP 和 Backbone.js
很少有,但是如果有任何架構性質的Javascript框架聲稱用其經典形式實現了MVC或者MVP模式的話,那是因為許多開發者并不認為MVC和MVP是相互沖突的(看到諸如ASP.net或者GWT這樣的web框架,我們實際上更加可能會認為MVP被嚴格的實現了)。這是因為讓我們的應用程序有一個附加的展示器/視圖邏輯,同時也仍然當其是一種MVC的意味,是有可能的。
Backbone貢獻者Irene Ros(位于波士頓的Bocoup)贊同這種想法,當她將視圖分離到屬于它們自己的單獨組件中時,她需要某些東西來實際為她組裝它們。這可以是一個控制器路由(比如Backbone.Router,在本書的后面會提到)或者一個對被獲取數據做出響應的回調。
這就是說,一些開發者確實感覺Backbone.js更加適合于MVP的描述,相比于MVC。他們的觀點是:
* 相比于控制器,MVP中的展示器更好的描述了Backbone.View(視圖模板和綁定在視圖模板之上的數據之間的中間層)。
* 模型適合Backbone.Model(相較于MVC中的模型并沒有很大的不同)。
* 視圖最能代表模板(比如 Handlebars/Mustache標記模板)
對此的回應會是視圖也可以是一個View(如MVC),因為Backbone對于讓它用于多用途有足夠的彈性。MVC中的V和MVP中的P都能夠通過Backbone.View來完成,因為它們能夠達成兩個目標:都用來渲染原子組件,還有將那個組件組裝起來讓其它視圖來渲染。
我們也已經看到Backbone中控制器的責任Backbone.View和Backbone.Router都有分享,而在下面的示例中我們能夠實際看到那方面實際上都是千真萬確的。
在this.model.bind("change",..)一行中,我們的BackbonePhotoView使用了觀察者模式來對視圖的改變進行“訂閱”。它也處理render()方法中的模板,但是并不像一些其它的實現,用戶交互也在視圖中處理(見events參數)。
~~~
var PhotoView = Backbone.View.extend({
//... is a list tag.
tagName: "li",
// Pass the contents of the photo template through a templating
// function, cache it for a single photo
template: _.template( $("#photo-template").html() ),
// The DOM events specific to an item.
events: {
"click img" : "toggleViewed"
},
// The PhotoView listens for changes to
// its model, re-rendering. Since tHere's
// a one-to-one correspondence between a
// **Photo** and a **PhotoView** in this
// app, we set a direct reference on the model for convenience.
initialize: function() {
this.model.on( "change", this.render, this );
this.model.on( "destroy", this.remove, this );
},
// Re-render the photo entry
render: function() {
$( this.el ).html( this.template(this.model.toJSON() ));
return this;
},
// Toggle the `"viewed"` state of the model.
toggleViewed: function() {
this.model.viewed();
}
});
~~~
另一種(完全不同的)看法是Backbone更加向我們前面考察過的Smalltalk-80MVC靠攏。
定期為Backbone寫博客的Derick Bailey之前已經提到過,最終最好不要去強迫Backbone讓其適應任何特定的設計模式。設計模式應該考慮指導可能如何被構建的靈活性,而在這一方面,Backbone既不適應MVC,也不適應MVP。相反,它從多個架構模式中借用了一些最好的經驗而創造出了一個靈活的框架,并且工作得很好。
而理解這些這些概念源自哪里和為什么源自那里是值得去做的,因此我希望我對于MVC和MVP的闡述對此已經有所幫助。就叫它Backbone方法吧,MV*或帶有的其它應用程序架構的意味。大多數結構性Javascript框架自主決定自身采用的經典模式,不管是有意還是無意為之的,最重要的是它們幫助了我們有組織,干凈的來開發方便維護的應用程序。
- 前言
- 簡介
- 什么是設計模式?
- 設計模式的結構
- 編寫設計模式
- 反模式
- 設計模式的分類
- 設計模式分類概覽表
- JavaScript 設計模式
- 構造器模式
- 模塊化模式
- 暴露模塊模式
- 單例模式
- 觀察者模式
- 中介者模式
- 原型模式
- 命令模式
- 外觀模式
- 工廠模式
- Mixin 模式
- 裝飾模式
- 亨元(Flyweight)模式
- JavaScript MV* 模式
- MVC 模式
- MVP 模式
- MVVM 模式
- 最新的模塊化 JavaScript 設計模式
- AMD
- CommonJS
- ES Harmony
- JQuery 中的設計模式
- 組合模式
- 適配器模式
- 外觀模式
- 觀察者模式
- 迭代器模式
- 惰性初始模式
- 代理模式
- 建造者模式
- jQuery 插件的設計模式
- JavaScript 命名空間模式
- 總結
- 參考