一點點感想:寫程序都快十年裏,幾乎沒有用過什麼大型的框架,實爲懺愧,其實對於設計模式仍是耳熟能詳,mvc,facade,factory模式等等,其實在本身代碼中都會用到,不過都是本身寫的,沒有框架那麼複雜,但可定是符合實際設計須要的。MVC設計模式主要是解決了代碼耦合性的問題,當爲此給程序帶來的理解問題就會多一些了,畢竟順序思惟仍是好理解一點。因爲項目中原來本身寫的MVC框架在代碼不斷的增長,已經變得難以理清頭緒了,尤爲是在Flex的時間和回調中交織時,變得由爲困難。遂決定用一個開源的MVC框架來理清個人問題。因爲須要設計的是一個須要高效運行的設計器,並且設計器中的元素會須要不斷的加載和刪除,使用Robotlegs框架就有點困難,他是經過監聽舞臺元素添加事件實現消息注入的,對設計器而言,須要不斷地加載和刪除就會產生效率問題,最後迴歸到了puremvc框架上了。其實,知道MVC模式和可使用,並用好MVC模式寫代碼,仍是須要一段時間的。MVC模式若是簡單的理解就是經過將模型,視圖用控制器分開來實現模型和視圖的鬆耦合,那麼如何實現的呢?有應該以什麼樣的方式來寫本身的代碼,並真正實現MVC鬆耦合的目的呢?本人經過本身的理解,來學習puremvc框架,以解決上述問題,本文的思路也是經過帶着問題的方式來逐步學習的。git
初始問題:github
本文經過puremvc的官方教程《puremvc實現術語闡述及最佳實踐》一書和Login的例程來學習的,筆者也是剛學習,但願能夠一同探討。閱讀本文須要Flex的基本知識和MVC基本概念,還有一顆對知識無線追求的心。web
首先,咱們經過書本上的知識來梳理一下MVC如何在puremvc中的體現。編程
如上圖所示,MVC三部分經過消息總線(MVC內部必須實現),來實現模型與視圖的分離,並經過控制器實現了業務邏輯的處理。對於常見的場景就是加載數據,用戶修改數據,再保存數據,在MVC模式下,加載數據有用戶在View上發起,經過Command交給Controller,Controller調用Model取得數據,當數據取得後,發送通知消息到消息總線,相應的View會接受消息,並完成數據的顯示,用戶在View上修改後,經過Controller再將數據寫回Model。如此就是一個MVC模式下普通的工做場景,這樣的好處是:View和Model相互的關聯性不多,View須要依據本身的需求呈現數據便可,Model實現本身的數據加載和存儲,若是須要修改View的代碼,Model部分就不須要修改,保持了代碼的局部穩定性。另外,消息總線很好地實現了一對多的消息傳遞,能夠實現多個視圖同時更新的需求。以上是MVC的簡單模式,在puremvc中,就具體化多了。設計模式
消息總線使用Notification對象傳遞,Controller經過Command進行處理,機制與前面講述的同樣,只是View有Mediator(中介),Model由Proxy(代理)處理具體的邏輯。這裏就回答了puremvc是如何實現MVC模型的問題了。併發
下面經過Login的具體例子來分析puremvc如何使用,以及他實現鬆耦合的。mvc
首先,若是須要下載代碼請下載Github上的代碼,不過筆者發現Flash Builder4.6沒法編譯,因此本身新建了一個工程PureMVCLogin的項目,若是有須要,我能夠傳到空間中。app
爲了理清Login程序的脈絡,我繪製了類圖,並表示了程序的初始化路徑(藍色關聯線條)。框架
再來一張時序圖,講述了Login各模塊的工做順序(可放大查看)。ide
Login的前期初始化順序就是從建立Facade開始的,Facade爲單例模式,經過ApplicationFacade.getInstance()創建Facade實例,完成實例化後偶,puremvc已經能夠開始內核就初始化完成了。下一步就是創建應用系統的相關工做做了。ApplicationFacade代碼以下:
public class ApplicationFacade extends Facade { /** * Notification name constants * */ public static const APP_STARTUP: String = "appStartup"; public static const LOGIN: String = "login"; /** * Singleton ApplicationFacade Factory Method */ public static function getInstance(): ApplicationFacade { if (instance == null) instance = new ApplicationFacade(); return instance as ApplicationFacade; } /** * Register Commands with the Controller */ override protected function initializeController() : void { super.initializeController(); // // register commands registerCommand( APP_STARTUP, ApplicationStartupCommand ); registerCommand( LOGIN, LoginCommand ); } public function startup(app: PureMVCLogin):void { this.sendNotification( ApplicationFacade.APP_STARTUP, app ); } }
在Application中開始取得facade的實例後,在Application的createComplete事件中執行facade的startup函數,該函數發送APP_STARTUP通知,並帶有app對象,app對象保護view相關的應用(在初始化後面的Mediator時須要),因爲在facade在initializeController中註冊了APP_STARTUP和LOGIN命令,在startup調用開始是,puremvc內核已經能夠工做了,接下來的事情就是初始化與具體應用相關的任務了。
ApplicationStartupCommand爲宏命令,即就有多個命令集合的對象,在Login中,他執行了ModelPrepCommand和ViewPrepCommand兩個命令,須要注意的是再宏命令中的命令是按順序執行的,即先初始化模型,在初始化視圖,而且,視圖初始化的時候,會經過facade取得相應的Proxy(代理)引用,所以是有順序要求的。模型的初始化任務就是創建並註冊相應的Proxy到框架中,視圖的初始化任務就是創建總的Mediator(中介)ApplicationMediator,並在其中創建並註冊Mediator到框架中。這樣,Login系統的mvc模式就初始化完了。
須要說明的就是Mediator與View之間是經過Flex的Event事件來傳遞信息的,具體編程模式請仔細看前面的官方教程。本例中LoginPanelMediator註冊了LoginPanel的登錄按鈕事件,即Mediator接管具體界面的事件,再把事件創建好能夠被其餘模塊處理的對象,並推送給框架(sendNotification),此時Mediator的任務已經完成,就只需等待登錄成功或失敗的消息了。框架接受到Notification事件後,會找到監聽了該通知的Mediator(通常用於多箇中介間通信)或Command(與代理通信)。Login例程中,LOGIN時間ApplicationFacade初始化的時候註冊了相應的命令,此時框架就會把命令對象建立,並調用Commande的execute方法,LoginCommand代碼以下:
override public function execute(note: INotification) :void { var loginVO: LoginVO = note.getBody() as LoginVO; var loginProxy: LoginProxy = facade.retrieveProxy(LoginProxy.NAME) as LoginProxy; loginProxy.getUser(loginVO); }
在上面的代碼中,經過名稱找到對應的Proxy對象,並執行登錄的業務邏輯,即調用getUser方法。這裏能夠看出Controller對Proxy的控制是接口關聯的,對於View而言不須要知道登錄如何處理,對Controller而言,他須要知道由哪一個命令來處理,命令須要知道如何與具體的代理通信,實現登錄命令。這裏並無方法返回,若是命令執行成功或失敗,就Proxy來發送具體的Notification,Proxy也不須要擔憂結果由誰來處理,它只須要知道如何取得數據,併發送通知便可,通知總線會找到相應的執行體來執行,若是沒有也不是發送者須要擔憂的。
// // populate its data object using the result var loginVO: LoginVO = event.result as LoginVO loginVO.loginDate = new Date(); setData( loginVO ); // // change the view state _appProxy.viewState = ApplicationProxy.LOGGED_IN_STATE; // // notify all interested members sendNotification( LoginProxy.LOGIN_SUCCESS );
在Login程序中,當從服務端成功取得登錄後,LoginProxy會通知ApplicationProxy修改他的viewState,併發送一個登錄成功的通知。該通在LoggedInBoxMediator的類中已經經過listNotificationInterests方法訂閱了改通知,這樣改通知就會由LoggedInBoxMediator處理,並最終體如今其關聯的LoggedInBox界面上,若是登錄失敗,方法與此相同,請仔細看前面時序圖的下半部分。
此時,登錄的功能已經在mvc模式的驅動下合做完成了。那麼爲何要這麼複雜的處理呢?經過Notification在View(Mediator)和Model(Proxy)之間流動,View和Model就徹底解耦了,只要Model保持穩定的接口(通知對象),那麼重寫View部分是,是不須要修改Model的代碼的。消息訂閱模式解決了須要思考負載事件傳遞的煩惱。好比在Flex開發中,咱們會用到不少的模塊(View),若是各模塊之間須要通信,那麼通常的寫法就是相互添加Listener或經過callback方式來傳遞數據,若是相關模塊數量不少的狀況下,這些傳遞數據的方式就麻煩了,各模塊修改本身的方法時還須要考慮其餘模塊是否會有問題(筆者在寫設計器的過程當中深受其害),若是應用puremvc,我會把各模塊經過Notification創建好通信機制,從而不用小心其餘模塊的實現問題了。好比在A模塊修改了一個對象,此時,B,C模塊就能夠經過監聽通知來改變本身的對象,做爲A模塊,至須要考慮發出通知,其餘的就不須要考慮了,這就是消息總線(Notification)的好處了。
此時第二個問題:puremvc是如何實現鬆耦合的就好回答了吧,經過Notification機制實現Model和View的鬆耦合。第三個問題:puremvc是如何來構建代碼的經過順序圖已經很好的說明了。
下面請思考:爲何存在直接註冊Notification訂閱的方法和registerCommand的訂閱方法?
.........
筆者看到Login事件經過Command實現,而LOGIN_SUCCESS和LOGIN_FAILED是經過listNotificationInterests方法訂閱的,爲何呢?仔細閱讀了官方教程後找到了答案?
Notification能夠經過上述兩種方式進行訂閱,而通常狀況下,須要複雜業務邏輯處理的使用Command處理,還有就是官方說Proxy發送但不接受Notification,即若是須要Proxy接受Notification是不行的,須要經過Command來執行Proxy的方法實現修改Proxy下面的Model數據。各Mediator能夠經過直接訂閱Notification的方法實現消息處理。請參閱官方教程中的:Mediator和Proxy之間、Mediator和其餘Mediator之間的耦合。
本文就Login的示例代碼深刻學習了puremvc在ActionScript中的應用,筆者也是在學習中,但願能夠共同窗習和交流。