原文:Deft JS: Loosely Coupled MVC through Dependency Injection
650) this.width=650;" border="0" alt="" src="http://www.bkjia.com/uploads/allimg/131228/131K1N36-0.png" />
應用才剛剛部署?作為經驗豐富的軟體開發人員,都知道不用多久就要做重大的使用者介面修改。無論如何深思熟慮,如何通過需求分析和設計與客戶達成一致,能避免修改的設計幾乎沒有。真正行之有效軟體,是能以最少成本適應不斷變化的使用者需求的軟體。
那麼……如何架構軟體,才能迅速實現使用者介面的變化,而不用破壞底層的基礎商務邏輯呢?
模型 視圖 控制器MVC)
在代碼中應用架構的起始階段,重點是將應用劃分成不同的嵌入式管理單元,每個嵌入式管理單元負責一個應用事務。為此,大多數應用採用模型-視圖-控制器架構模式。實現這種模式有多種方式,軟體開發專家馬丁將這些實現模式經過收集和整理,並編錄在這裡。
通常,一個MVC架構包括:
- 模型:描述和管理應用資料的行為和狀態,並根據請求做成相應的響應或修改狀態。
- 視圖:將模型資料顯示給使用者,接受使用者輸入,並監聽使用者行為,如單擊或選擇操作。
- 控制器:模型和視圖之間的中介,監聽使用者行為並相應的在模型上執行操作,然後重新整理視圖以反應模型的變化。
通過控制器通過觀察商務邏輯分離的使用者介面組件和布局視圖),然後觸發商務邏輯更新應用資料,可使應用更好的適應不斷變化的業務需求。
Deft JS MVC
Deft JS是增加的Sencha MVC架構,主要包括:
- 模型使用通常faceless)的商務邏輯組件,如Ext.data.Store、Ext.Data.Model。
- 視圖可使用Ext JS這個豐富的開發包或Sencha Touch內的容器和組件。
- 控制器則通過建立繼承於Deft.mv.ViewController對象的特定視圖控制實現。
Deft JS視圖控制器
通常,一個視圖就是一個包含多個組件組成的容器。一個視圖控制是yield輕量級的控制器,負責管理指定視圖的及其子組件的狀態,監聽視圖及其子組件的事件,並響應使用者操作,並委託工作以便注入業務模型和服務如Ext.data.Stores、Ext.data.Models等)。
在Deft JS,一個視圖通常是一個Ext JS類的填充了子組件的子類。視圖定義要混入Deft.mixin.Controllable對象,同時要聲明相關的視圖控制器類名。每一個視圖,都要建立一個對應的,從Deft.mvc.ViewController擴充的視圖控制器類。這個特定的視圖控制需要設定其引用相關的視圖組件,並註冊視圖控制器的方法來處理視圖組件的事件。
Deft JS視圖控制器及混入的Controllable的主要功能是:
- 支援指定視圖的多個獨立執行個體,每一個視圖都有其唯一的視圖控制器執行個體。
- 通過自動建立和銷毀視圖控制器及其相關的視圖,以減少記憶體。
- 為引用視圖組件和為視圖控制器的方法註冊監聽事件 提供簡潔的配置。
- 在整合的視圖的生命週期內,運行移除或銷毀視圖控制器。
- 自動刪除視圖、視圖組件引用和事件監聽,以簡化清理操作。
Deft JS依賴注入
許多模型、視圖和控制器對象都不是獨立的self-contained)。它們會引用或委託一些工作給其它對象。這些被引用的對象就會成為依賴。通常,你可以顯式地建立這些依賴的執行個體或者從服務定位器手動請求它們。
在應用組件之間鼓勵實現低耦合,Deft JS包含一個輕量級用於依賴注入的反轉控制IOC)。當執行IOC主體時,可以通過類聲明列表代替手動建立或擷取依賴類。當類需要延遲執行個體化,IOC容器會負責處理這些依賴所需的正確的對象執行個體,並在運行時將它們注入類。
有了IOC,在類中就不再需要建立依賴類,或者明確定義這些依賴類。此外,它不再需要綁定依賴類的特定實現。通過提供預期的API,可以配置IOC容器注入一個完全不同的實現。
因此,你可以很容易的通過配置IOC容器來類比任何的依賴類版本來測試你的類。你也可以建立多個不同的應用,在每個應用的IOC容器內配置使用不同的依賴類實現,如Store和Proxy。例如,可配置使用靜態JSON檔案驅動的類比Store和Proxy;也可以配置為通過JSONP使用production服務的Store和Proxy。
Deft JS IoC容器及其混入的Injectable的主要功能包括:
- 支援單件模式、類執行個體原型的分解和原廠模式的依賴關係
- 在Ext JS類的建構函式執行之前,在配置項和屬性注入依賴
樣本
設想在一個連絡人管理應用的視圖內包含yield連絡人Grid:
- Ext.define( 'ContactsApp.view.ContactGridView',
- extend: 'Ext.container.Container',
- mixins: [ 'Deft.mixin.Controllable', 'Deft.mixin.Injectable' ],
- inject: [ 'contactStore' ],
- controller: 'ContactsApp.controller.ContactGridViewController',
-
- config: {
- contactStore: null
- },
- ...
- initComponent: function() {
- this.items = [{
- itemId: 'contactsGrid',
- xtype: 'gridpanel',
- store: this.getContactStore(),
- ...,
- bbar: Ext.create( 'Ext.PagingToolbar', {
- store: this.getContactStore(),
- ...
- })
- },
- ...
- {
- xtype: 'container',
- ...
- items: [{
- itemId: 'editButton',
- xtype: 'button',
- text: 'Edit'
- }],
- ...
- }];
- }
- );
視圖類的定義通過混入Deft.mixin.Injectable,及它的依賴通過“inject”聲明,已經具備忘入功能。
當視圖通過Ext.create()或 Ext.widget()執行個體化的時候,Ioc容器將處理“contactStore”的依賴和注入相關的值到“contactStore”的配置。產生的getContactStore()方法將會返回注入值。
另外,視圖類通過混入Deft.mixin.Controllable,及使用“controller”聲明控制,具備了控制功能。
當視圖執行個體化的時候,指定的視圖控制器會被建立及被配置引用視圖。當視圖銷毀的時候,視圖控制器也會被銷毀。
- Ext.define( 'ContactsApp.controller.ContactGridViewController',
- extend: 'Deft.mvc.ViewController',
- mixins: [ 'Deft.mixin.Injectable' ],
- inject: [ 'contactStore' ],
-
- config: {
- contactStore: null
- },
-
- control: {
- contactsGrid: {
- click: 'onContactsGridClick'
- }
- editButton: {
- click: 'onEditButtonClick'
- }
- },
- ...
- destroy: function() {
- if (this.hasUnsavedChanges) {
- // cancel destruction
- return false;
- }
- // allow destruction
- return this.callParent( arguments );
- },
- ...
- onEditButtonClick: function () {
- this.getEditButton.setDisabled( false );
- },
-
- onContactsGridClick: function () {
- // add a ContactEditorView to the TabPanel for the selected item
- ...
- },
- );
視圖控制器擴充自抽象基類Deft.mvc.ViewController,它提供了一個“control”配置項用於簡化視圖組件的訪問器的建立及為它們綁定事件。
樣本中,Gird和按鈕可通過itemId也支援自訂選取器)引用,它們的單擊事件控制代碼則定義為視圖控制器的方法。兩個訪問器函數會自動建立:getContactsGrid() 和getEditButton()。當視圖被銷毀時,視圖控制器的destroy方法會被調用,通過它可以阻止視圖銷毀。如果該方法返回true,視圖將被銷毀,所有在視圖控制器通過“control”定義建立的引用和監聽事件會自動被刪除。
Ioc容器通常在主應用的javascript檔案中的Ext.onReady()內定義,調用Deft.Injector.configure()方法。
- Ext.onReady( function () {
- Deft.Injector.configure({
- contactStore: 'ContactsApp.store.ContactStore'
- // contactStore: 'ContactsApp.store.MockContactStore'
- });
- });
在樣本中,Deft JS Ioc容器已配置執行請求ContactsApp.store.ContactStore的單件模式執行個體“contactStore”。注釋行顯示如何簡單的使用指定類比類來代替它。
關於Deft JS
Deft JS是一個使用MIT協議,擴充自Ext JS和Sencha Touch API的開源架構,它提供:
- 優雅的非同步作業鏈和使用Promises及Deferreds的資料處理。
Created by a team of software architects working at the innovative digital solutions agency Universal Mind, Deft JS leverages best practices and proven patterns refined over years of delivering cutting edge solutions across a wide range of platforms and devices.
作者:John Yanarella
John Yanarella is a Principal Architect at Universal Mind, an innovative digital solutions agency that fuses the design capabilities of an interactive firm with the the technical expertise of a systems integrator. He is passionate about breaking complex problems down into simple reusable solutions; he created Deft JS and has been a principal author and contributor to several other commercial and open-source frameworks. Follow John on Twitter @johnyanarella.
Deft JS:http://deftjs.org/
譯者著:使用Deft JS確實比使用Ext JS自身的控制類簡單,值得使用。