轉自:http://www.iamsevent.com/post/36.html
使用架構:AS3
任務描述:了解PureMVC架構使用方式,了解普通AS3使用HTTP請求進行網絡互動的方式,了解PureMVC架構設計思想
難度系數:2
先簡單闡述一下PureMVC中的幾大要點吧:
①PureMVC中存在一個叫做Facade的類,它是PureMVC的核心類,負責管理排程PureMVC中的成員互動和運作。一般來說,一個應用中建立一個facade對象就夠了。
②PureMVC中主要有三個角色:Mediator、Command以及Proxy。這三個角色分别對應着我們通常所說的MVC思想中的V(視圖)、C(控制器)、M(資料管理器)。它們隻有被注冊到facade類中才能運作,才有意義。通過調用facade對象的registerMediator、registerCommand或registerProxy方
法可以将它們注冊到facade對象中去。一旦被注冊到facade對象中去了之後,享用同一注冊源的Mediator、Command以及Proxy對
象就可以通過notification(通知)進行彼此之間的通訊,notification類似于AS中的事件,隻不過notification是在全
局進行派發罷了,而事件隻有事件派發者本人或其顯示清單的父容器才能偵聽到。使用notification進行通訊是PureMVC最大的便利之處。在一個Mediator、Command或者Proxy對象中使用sendNotification方法可以派發一個notification通知:
該 方法的首個參數代表該條notification的名字,確定notification的名字的唯一性是減少意外錯誤的最佳保證。如果你願意,你可以為該 方法傳入第二個參數作為該條notification所攜帶的資料,可以是一個String, int或者是Object、Array等複雜對象。
notification的派發方式是一樣的,但是接受方式有些不同,對于Mediator對象來說,我們需要通過重載listNotificationInterests方法為它列出其感興趣的notification清單,如果在一個notification被發出時,該Mediator對象通過檢視該notification的名字來判斷該條notification是否是自己所感興趣的,若感興趣,則會調用handleNotification方法來對該notification進行處理:
listNotificationInterests方法的傳回值必須是一個數組,而且該數組中的内容不能動态改變。當一個Mediator對多個notification感興趣的時候,可以在handleNotification方法中使用switch...case語句針對不同名字的notification執行不同的邏輯,若是在派發通知時在sendNotification方法中設定了第二個參數,那麼可以在處理通知時使用notification對象的getBody方法來擷取通知所攜帶的資料。
對于Command對象,若要讓它接受notification通知,就必須為該Command在facade中注冊notification對應關系:
一個Command需要響應多少種類的notification就需要多少條注冊語句,注意Command的使用方法,我們沒有必要去 執行個體化一個Command對象,而僅僅需要建立一個Command類,之後為該類注冊notification響應關系即可。注冊完畢之後我們需要在 Command類中通過重載execute方法來為Command編寫通知處理邏輯:
其中邏輯基本上與Mediator的處理模式是一樣的。對于Proxy來說,它不具備響應notification的能力,這樣也使得其Model(資料管理者)的角色更加純粹一些,資料管理者本身就沒有必要參與到應用程式的業務邏輯中去。
一旦某個M、C或者P被注冊到facade中,它們中的facade屬性就會持有注冊到的facade對象的引用,然後我們可以在任意時候調用該屬性的retrieveMediator方法擷取到某個名稱對應的Mediator對象。如我們使用剛才注冊的那個名字去facade中取到相應的Mediator對象:
類似地,我們可以使用使用facade屬性的retrieveProxy方法擷取到指定名稱對應的Proxy對象。這是除了notification外的 另一種通訊方式,隻不過該方式耦合性稍高一些。如果在某些情況下Mediator要擷取Proxy的資料,就可以通過該方法拿到。
③關于這三者的使用方法,在AS項目中,我們會為一個視圖子產品套上一個Mediator對象。類似這樣:
Mediator的構造函數預設接受兩個參數,第一個指的是該Mediator的名字,一旦被指定了一個名字,該Mediator對象就會以該名字被注冊 到facade中去;第二個參數則是該Mediator所關聯的視圖對象,關聯了一個視圖對象之後,Mediator可以通過其viewComponent屬性來通路它所關聯着的視圖對象。
通 過為Flash顯示清單中某個顯示對象建立與Mediator的關聯,我們這就讓顯示清單與PureMVC架構之間銜接了起來。在Mediator中對其 所關聯顯示對象viewComponent偵聽事件,我們就可以在viewComponent需要擷取資料或做一些其自身所無法完成的大事時借助 PureMVC的力量予以完成掉。下圖展示的是一個項目中,Flash顯示清單與PureMVC之間的通訊關系:
由 此圖我們可以看到,在顯示清單中的顯示對象在外圍包裹了一層Mediator之後,如果它需要擷取資料,隻需要派發一個事件即可,顯示對象自身無需知道數 據擷取的過程,它隻是衣來伸手飯來張口,我TM要資料的時候你TM就乖乖給我拿過來,老子不管你用了什麼方式!若是你已準确地在Mediator中為相應 事件添加了事件偵聽器,那麼在收到來自其所關聯的顯示清單中派發出來的事件後就可以開始通過notification讓PureMVC架構運作起來了,若 要擷取資料,那麼該notification會被Command相應并調用Proxy的API,由Proxy負責網絡互動,待取到資料後使用 notification發送回Mediator;若要切換面闆(如點選顯示清單中某個按鈕後打開另一個面闆),則發送的notification會被要 切換到的面闆所關聯的Mediator相應并執行相關切換面闆的操作。
光看文字有點抽象,但是我也不太可能出視訊。 是以隻能結合一點執行個體來理論結合實踐一下。由于我自己不會寫背景,是以隻能找網上一些公開的API,用得比較多的一個是雅虎的天氣API,這個的使用方法 也比較簡單,稍後我們就會看到。在本教程中,由于安全沙箱的問題,不能将示範的swf放上來,是以還得列位下載下傳源碼後在自己的機器上編譯運作以檢視結果, 現在隻放出一個運作結果的截圖以供列位在腦中有個小小的印象:

很簡單對吧?隻需要擷取一下天氣資訊再顯示出來就好了,資料和圖檔都從雅虎網站上加載,是以要看到效果,必須讓你的機器處于聯網狀态才行。
好 了,搓搓手,let`s fucking start our game, baby! 首先是建立文檔類,然後在文檔類中,若要啟動PureMVC架構,就必須建立一個facade執行個體。由于我們目前做的是一個天氣預報程式,是以咱們的 facade類就取名叫WeatherFacade好了:
在建立了facade之後,我們想把一些初始化工作放到一個Command裡去做,因為初始化的代碼不涉及到Mediator和Proxy。但是之前說 過,在PureMVC中,一個Command隻有被注冊到了facade中才有意義,才能運作。在facade啟動時會調用其一個名叫initializeController的 方法來執行一系列Command的注冊工作,我們就把做初始化工作的Command(我這裡命名為ApplicationCommand)在該方法中執行 注冊工作。注冊完畢後,我們讓WeatherFacade開放一個公共API出來,以便外部在想要啟動facade的時候可以随時啟動。我将該API命名 為startup,在該方法中隻執行一句代碼,就是派發我們之前注冊的與ApplicationCommand相關聯的通知(這裡出現的 NotificationDictionary類是一個我建立的用于記錄該應用中所有可用的notification名字的類)。在派發該通知之後會發生 什麼事?對,這位同學回答得很好,會執行與它關聯的Command的excute方法。下面給出的是ApplicationCommand類的代碼:
在pureMVC中提供了兩種類型的Command以供我們選擇:MacroCommand和SimpleCommand,前者可以讓 你一次性按順序執行多個Command,後者則一次隻執行一條Command,總而言之,SimpleCommand是單一命 令,MacroCommand是多指令。在我的實際應用中,基本上極少會用到前者,一般使用後者就足以滿足我們的使用需要了。在 ApplicationCommand的excute方法中我們隻執行一句踹死語句,這意味着現在,當我們通過調用我們的 WeatherFacade.startUp方法啟動應用後,會看到控制台輸出一句"application startup",除此之外不會發生任何其他事情。稍後,我們會在該excute方法中添加其它的一些邏輯。現在,我們先建立出我們的文檔類 WeatherTest.as,并試着啟動我們的WeatherFacade看看。
由于WeatherFacde被我做成了單例,是以我們可以在文檔類中很友善地拿到其全局唯一的執行個體并執行其啟動方法。我這裡還使用了一句 Systen.useCodePage = true 是為了讓我在向雅虎擷取天氣資料時不至于出現亂碼。如果你現在執行我們的文檔類WeatherTest,你将會如期看到控制台輸出了一條應用已啟動的消 息。到此為止,列位應該已經了解了pureMVC中Command和notification的使用方式了。那麼接下來,讓我們繼續來點好玩的,Come on!
我們知道,我們在做Flash應用的時候通常會把文檔類作為最上層父容器,其他建立的圖形啊面闆什麼的都會addChild在文檔 類或其子對象上面。那麼在pureMVC中,為了延續我們的習慣,我們需要讓啟動應用的Command——ApplicationCommand持有文檔 類的引用才行。為了達到這個目的,我在WeatherFacade.startup方法中添加了一個WeatherTest類型的參數,并将該參數放在 notification中攜帶數去
之後,在ApplicationCommand的excute方法中取出其接收到的notification對象攜帶的文檔類引用并持有之:
最後,我們隻需要在文檔類中,将文檔類自身的引用傳遞給WeatherFacade.startup方法就行了。
在ApplicationCommand持有了文檔類的引用之後我們就可以在ApplicationCommand.excute方法中執行一系列我們熟 悉的addChild及removeChild等操作來為舞台上添置東東了。在添置東東之前,我們先想想,我們舞台上要放置點神馬東西呢?首先,是一個面 闆,上面有多個按鈕,每個按鈕代表一個城市,我點選哪個城市的按鈕就可以查詢哪個城市的天氣預報資訊!為了簡便起見,我使用了以前教程中用到的一些按鈕、 面闆元件,源碼就不放出了,感興趣的道友可以直接下載下傳源碼進行檢視。我們首先建立的導航面闆NavigationPanel代碼如下:
首先,該導航面闆類繼承自Canvas類,Canvas類是我自定義的一個繼承自Sprite的類,它實作了面闆的一些基本功能,包括繪制背景,設定固定 大小的功能。在導航面闆的構造函數中我将它的mouseEnable設定為了false,這是為了使我在為它添加滑鼠點選事件的時候,事件對象的 target屬性不會指向它自身,這樣就保證了我每次隻有點選其内部的子顯示對象才會觸發CLICK事件,我點選子顯示對象區域之外的背景區域都不會派發 CLICK事件了,這樣就不必為每個子顯示對象都注冊一個CLICK事件偵聽,隻要一個事件偵聽器就可以達到偵聽點選事件的目的。這也是我常用的一個小技 巧。
另外,NavigationPanel的setItems方法可以讓我們很友善地建立出将出現在導航面闆中的按鈕項目,我們隻需要提供 一個滿足一定格式的數組(在setItems方法的注釋中有說明),導航面闆就會根據該資料來建立出相應的按鈕并自動調用 updateDisplayList方法來實作排版工作(CustomButton類是一個灰底黑字的按鈕元件,在構造函數中傳入的是一個代表按鈕文字的 String對象)。
好了,建立完了導航面闆後,我們還需要一個用來顯示某個城市詳細天氣資訊的資訊面闆,該面闆将會在我點選導航面闆中某個城市的按鈕後打開,它的效果圖如一開始給出的應用預覽圖一緻。先上完整代碼:
咋看之下代碼很多,但是細細看來,其實也沒多少東西。以上代碼中除了資訊面闆之身之外還包含了一個叫做ForcastView的包外類,該類将被用以表示 每天的天氣資訊(包括天氣圖示,溫度、天氣描述文本),我想顯示幾天的天氣資訊,就建立幾個ForcastView對象。該對象的資料提供源來自一個 ForcastVO類,該類中記錄了如下幾個資訊:
當isCurrent屬性為true時,ForcastView的時間部分将顯示為“目前”,溫度隻顯示目前溫度;否則,時間部分将顯 示對應星期幾,溫度會顯示最高到最低溫度。由于該類隻會在InformationPanel中用到,我就直接把它作為包外類了。有了該類之後,我在 InformationPanel中建立了三個它的對象,一個用來表示目前天氣資訊,剩下兩個用來表示接下來兩天的天氣預報資訊。另外,我還建立了一個 “傳回”按鈕用以回到導航面闆,點選它之後将會派發一個事件,該事件将會被InformationPanel的父類偵聽并處理。如果要設定 InformationPanel的天氣資訊,調用setInfomation方法即可達到目的,如果要讓我們在加載時顯示等待文字,可以調用 showWaitingText方法。
接下來,我們需要一個來包含NavigationPanel及InformationPanel,并根據使用者的互動來适時切換兩個面闆的顯示狀态。為此,我們建立了WeatherPanel類:
作為一個面闆管理者,它不需要具備太多的功能,主要職責就是偵聽來自子面闆派發的冒泡事件并執行相應的面闆顯示狀态切換就好了。WeatherPanel 繼承自Panel類,而Panel類又繼承自Canvas,是以Panel類擁有Canvas的全部功能(能繪制背景,可設定固定尺寸),并且還增加了一 個标題欄,拖拽标題欄可以帶動整個面闆的移動。
好了,看完了乏味的幾個視圖類之後總算等到了我們PureMVC中幾員大将的登場。之前說過,一個視圖子產品要想與外部通訊,必須通過該視圖子產品外層嵌套的Mediator來代理。那麼為此,我們隆重介紹一下寡人的愛将——WeahterPanelMediator。
我在關鍵部分都寫了注釋,另外,在Mediator被注冊後會立即調用onRegister方法,我們可以在該方法中寫一些初始化的代碼,在本例中,我為其所關聯的WeatherPanel類進行了以下初始化工作:
1.設定導航面闆中隻顯示兩個選項:北京和上海;
2.切換其初始化視圖狀态為“導航面闆”顯示狀态
3.偵聽導航面闆中某選項被選擇事件
在 某選項被選擇事件CustomEvent.ITEM_SELECTED被派發後,WeahterPanelMediator将會派發出一個名為 NotificationDictionary.GET_WEATHER的notification,這個通知派發出去後會發生什麼事情,我們尚且不管, 反正我WeahterPanelMediator隻知道,我要擷取天氣預報的資料就必須派發這個通知出去(同時将我要擷取的天氣預報城市名放在 notification中攜帶出去)。然後等天氣預報資料擷取到之後會收到一個名為 NotificationDictionary.ON_GET_WEATHER的通知,我将該通知列為WeahterPanelMediator所感興趣 的通知(在listNotificationInterests方法中列出),并在通知處理方法handleNotification中将擷取到的天氣數 據傳遞給其所關聯的weatherPanel去顯示。
接下來,我們要面對的問題是,讓誰去響應WeahterPanelMediator發 出的NotificationDictionary.GET_WEATHER這個通知。之前我們說過,Proxy無法直接對notification做出 響應,那麼此時我們就需要一個Command來做中介了。為此,我們建立了GetWeatehrCommand:
該類通過我們之前所提到過的facade.retrieveProxy方法擷取到了我們用來做網絡互動工作的Proxy——WeatherProxy的引 用,并在excute方法中把收到的notification(該notification名稱事實上就是 NotificationDictionary.GET_WEATHER,稍後我們會在ApplicationCommand中為它和 GetWeatehrCommand注冊起對應關系,若不注冊,則GetWeatehrCommand永遠也收不到該通知)中攜帶的資料,也就是我們要獲 取天氣預報的城市名傳遞給WeatherProxy的getWeather方法,WeatherProxy将會通過該方法來發送網絡請求,擷取對應資料。 接下來讓我們一起來看看WeatherProxy類的代碼,看看它内部是如何工作的:
好了,有了Mediator、Command以及Proxy後,我們差不多快大功告成了,最後在ApplicationCommand中,将我們之前所寫的零件都配備、組裝起來:
好了,這時若是你運作整個項目的代碼,應該能夠看到一個比較完整的結果了,若是不想敲代碼,直接在文章頂部下載下傳源碼便是。這是一個非常簡單的例子,卻涵蓋 了PureMVC的使用方式,整個PureMVC的運作流程,我已經在之前用一張圖表示過了。在本次實踐下來,我們可以體會到PureMVC的哪些優勢 呢?我列出了以下幾點:
1.通過notification機制降低了整個架構的耦合度。Mediator想要擷取資料,直接發一個 notification出去即可,老子隻要資料,具體怎麼擷取的,老子不管!老子隻要結果,不要過程!反正Mediator是最屌的,Command和 Proxy都是打工仔,Command一般是作為中介的存在,而Proxy一般隻負責資料擷取、處理以及保管,若有需要,你可以把某些Proxy做成單 例,在整個項目中都可以随時向它們擷取資料。如此明确的分工造就了PureMVC相當低的耦合度,以緻于讓其非常适合團隊開發。每個程式員隻管自己子產品的 功能實作,不必關心别的子產品中的代碼,每個子產品間通過notification通訊,非常簡單。比如程式員A對程式員B說:“喂,我這邊子產品上有一個按 鈕,按下之後要打開你做的那個面闆,我該怎麼辦?”“哦,你發個名字叫做XXX的notification就好了……”是的,你不用關心太多事情,在需要 使用别人開發的功能時,往往在需要的時候發一個notification即可解決問題。
2.PureMVC是一個成熟的,并且被廣泛使用的 架構。正因為使用它的人多,是以大家基本上都懂得遊戲的規則,在一個公司招聘員工的時候,若新來的員工懂PureMVC的用法,他就能很快地看懂目前項目 的源碼,并在其中可以快速查找、修改。最重要的是,新來的這名員工在寫了新的代碼之後不會随便亂放,他會根據現有的項目目錄結構來安排檔案放置位置。要調 用别人負責子產品的功能的時候也是簡單地發一條notification就可以實作。總而言之,一個熟悉PureMVC的新員工在加入一個使用 PureMVC架構進行開發的團隊中時能夠非常快地融入進去,這其實也是那麼多公司在招聘啟事上寫“要求熟練掌握PureMVC”的原因。
光說是沒有用的,列位道友還是得靠多實踐,多看多用方能領悟其中之奧妙。結束語不多說了,列位中秋、國慶快樂吧!