天天看點

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

robotlegs輕量級as3架構

任何一個好的東西(語言、架構等)最終還取決于用的人

語言和架構本身并不能保證使用者的代碼清晰、解耦等,

當然它隻是盡可能地做到這點。

robotlegs是一個用來開發flash,flex和air應用的純as3微架構(架構)。robotlegs專注于将應用程式各層排布在一起并提供它們互相通訊的機制。robotlegs試圖通過提供一種解決常見開發問題的經過時間檢驗的架構解決方案來加速開發。robotlegs無意鎖定你到架構,你的類就是你的類的樣子,而且應該很容易地切換到其他架構。

架構提供一個基于model-view-controller元設計模式的預設實作。這個實作提供一個針對應用程式結構和設計的強烈建議。雖然它确實輕微減低了你的應用程式的便攜性,不過它依然以最低限度影響你的具體類為目标。通過擴充mvcs實作類,你可以獲得很多有用的方法和屬性。

你不必使用robotlegs的标準mvcs實作。你可以使用它的任意部分,或者完全不使用它,或者使用自己的實作來适應你的需求。它是為了提供合适的參考實作和快速開始使用robotlegs而被包含進來。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

mvc就是(model view controller)模型-視圖-控制器,是一個設計模式(也可以稱為架構模式),但目前在大部分人眼裡顯然并不隻有這點意義。受到各種mvc架構的影響,消息通信,依賴注入,隔離編譯等等概念現在都加入到了mvc的概念裡,而且因為應用上的重疊和相似性,還常常和三層架構的概念混淆。

“一千個人眼中有一千個哈姆雷特”

一個名詞的意義,是由人們的了解來決定的,是以這裡從最基本的概念入手。

對于一個用于顯示的程式,最開始,隻有view(視圖)。

們要獲得一個資料并顯示,就是寫段代碼調用接口,獲得資料,然後根據資料更新視圖。而這裡的資料隻是一個臨時變量,或者存在于視圖的某個屬性中。顯然,這

樣做的話,資料是依賴于視圖的,如果不通過視圖,或者視圖根本不存在的時候,其他子產品就通路不到這個已經傳回的資料,則需要重新調用一次,這顯然是一種浪

費,而且也不便利。是以<b>我們在這裡将資料儲存到别處,和視圖不共享同一生命周期,那麼這分離出來的資料則被規定為</b><b>model</b><b>(模型)。</b>

(在這裡我必須打斷說明下,模型!=資料,僅僅是在這個簡化例子裡模型==資料。模型是為視圖提供内容的單獨子產品,具體内部是什麼情況則是各種各樣的,提供資料隻是它的功能之一)

此,就是最基本的分離表現層的原則。然而,有個地方卻是分不開的——原來控制加載資料的這部分代碼。它負責的是擷取資料,并訓示視圖根據資料更新的任務,

而它的去向有兩個選擇:要不加到視圖上(這是通常的做法),要不加在模型上(如果需要模型對應多個視圖),反正他不可能因為分離就憑空消失。那麼<b>我們把這部分代碼提出來作為單獨的部分,就是</b><b>controller</b><b>(控制器)。</b>

旦分離出了控制器,聯系模型和視圖的具體代碼就不再處于兩者之上(當然調用代碼還是有的),而是一個獨立的部分。它有自己的名字,而且不會和其他不相關的

内容混合在一起,非常清晰,容易定位。而模型和視圖從此也隻關心控制器,而不關心對方。他們的代碼都是處理自己的事情,别人的事情全部交給控制器去辦,這

使得他們自己的功能也非常獨立,減少了需要考慮的要素。

隻是代碼位置的移動,但是這樣移動後,将牽涉内容最多最易變,但是代碼量最少的代碼單獨放入控制器中,并妥善管理。相當與将分散在房間各處的開關集中于一

處,排列整齊并标注名字,做成遙控器在手裡把玩,從此就能從奔波于房間各個位置,尋找隐藏在角落裡的小突起的日常活動中解放出來。其意義,不言而喻。

而這,作為mvc的作用,已經足夠了。

一旦我們将視圖,模型,控制器分離後,可以做到什麼呢?

為視圖和模型都隻用處理自己的事情,對控制器的調用隻是一句代碼而已,那麼,它們實際上就可以被隔離出去。負責這部分代碼的人隻需要關心自己的事情,而不

需要關心整個環境。同樣的,編寫控制器的人隻需要知道視圖和模型的對外接口,而不需要了解它們的具體實作,也就是隻需要關心環境。這使得不同開發者需要的

知識被分隔開,每人隻需要了解有限的少量知識,最終卻又能順利合并在一起。

這是就是協作分工的基礎。

在這之後,三者的關系隻存在簡單的調用代碼。那麼<b>為了能夠徹底的分離和解耦,就可以将調用代碼改為發送消息或者其他的動态形式,這樣就能在沒有其他部分的時候獨立編譯</b>。由不同人在不同的工作環境獨立完成自己的部分,并在最後釋出時候簡單合并在一起,這确實是最理想的協作模式。

做到這點需要一個消息架構,而這就是mvc框

架的主要任務。除此之外,各種不同的架構還會加入其它設計模式,提供各種附加功能,自動依賴注入就是其中一項。還可能加入其它的中間件,進一步分割層次,

諸如分離出視圖其中的邏輯部分,使得繪圖和位置代碼不會和邏輯代碼混合,友善分工以及修改。使用觀察者模式,使得資料部分的修改可以自動同步到視圖上,如

此這般……mvc架構指的是“實作mvc的架構”,而非“隻實作mvc的架構”,僅僅實作mvc,這個架構的功能太過貧乏了,畢竟mvc也就是那種程度的東西。

最終,完成了這些之後,就成為了一般人表面看到的東西。雖然各式各樣,我們都将其稱之為“mvc架構”。

下面對比下比較熱門的幾個as3架構:

<b>framework</b>

<b>dependencies management</b>

<b>event management</b>

<b>presentation pattern</b>

<b>cairngorm</b>

singleton

singleton dispatcher

code behind

<b>puremvc</b>

service locator

notification

mediator

<b>mate</b>

dependency injection

display list

presentation model

<b>swiz</b>

<b>parsley</b>

central dispatcher

<b>robotlegs</b>

event bus

mediator or others

“puremvc和cairngorm是兩個較早出現的架構,目前我不建議再使用它們。puremvc的問題在于過于強調分離而缺乏實際功能,提供的便利很難抵消它本身的消耗,成本效益較低。cairngorm的問題則在于過于強調模型更新視圖的流程,限制太多,靈活程度不夠。

後出的幾個架構就好多了,mate使用了一個全局事件定義,配合flex寫法非常簡略。swiz則是用控制反轉+依賴注入,也就是spring的做法,而且元标簽注入的方式很有趣,感興趣的可自行查閱資料。”

“robotlegs裡使用了flash的事件機制來通信,而puremvc使用自定的通知來發消息。這裡差別不大,隻是使用事件機制就得寫事件類;然後robotlegs使用自動mediator自動注冊,它靠偵聽addtostage來處理,當然,手動注冊也是允許的。這樣友善了不少,puremvc隻能手動在視圖元件初始化時注冊,而且有時有些内部元件經常會出現未初始化完成時就去注冊,導緻通路不到this。還有最重要的依賴注入,robotleg不再使用puremvc那樣的傳遞參數方法,而是使用依賴注入,包括mediator對view元件的引用都是注入的。這樣依賴性又小了很多,感覺非常不錯。”

個人認為robotlegs比puremvc好用,robotlegs是puremvc的改進更新版而且是<b>專注于</b>as3的,注入技術更是省去了puremvc的許多麻煩。

robotlegs使用了以下3個面向對象設計模式:

ü  自動依賴注入(<b>automated dependency injection</b><b>)</b>,不用對象自己建立、擷取依賴的對象,而是由容器/架構來完成。

ü  指令模式(<b>command pattern</b><b>)</b>,

n  指令模式的本質是對指令進行封裝,将發出指令的責任和執行指令的責任分割開;

n  每一個指令都是一個操作:請求的一方送出請求,要求執行一個操作;接收的一方收到請求,并執行操作。

n  指令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎麼被接收,以及操作是否被執行、何時被執行,以及是怎麼被執行的。

ü  排程者模式(<b>mediator pattern</b><b>)</b>,定義一個中介對象來封裝系列對象之間的互動。中介者使各個對象不需要顯示地互相引用,進而使其耦合性松散,而且可以獨立地改變他們之間的互動。

robotlegs圍繞<b>依賴注入</b>設計模式展開。最簡單地,依賴注入是為對象提供執行個體變量或屬性的行為。

當你傳遞一個變量到一個類的構造函數,你在使用依賴注入;

當你設定一個類的屬性,你在使用依賴注入;

如果你不是使用嚴格的過程或線性方式編寫as3,很可能你現在就在使用依賴注入。

robotlegs使用基于中繼資料的自動依賴注入。這是為了友善開發而提供,而且在排布應用程式并提供類和它所需要的依賴時,可以減少很多代碼量。雖然完全可以手動提供這些依賴,但是允許架構來履行這些職責可以減少出錯的機會,并且通常可以加快編碼程序。

依賴注入(dependency injection,簡稱di),是一個重要的面向對象程式設計的法則來削減計算機程式的耦合問題。依賴注入還有一個名字叫做控制反轉(inversion of control,英文縮寫為ioc)。依賴注入是這樣一個過程:由于某客戶類隻依賴于服務類的一個接口,而不依賴于具體服務類,是以客戶類隻定義一個注入點。在程式運作過程中,客戶類不直接執行個體化具體服務類執行個體,而是客戶類的<b>運作上下文環境</b>或<b>專門元件</b>負責執行個體化服務類,然後将其注入到客戶類中,保證客戶類的正常運作。即對象在被建立的時候,由一個運作上下文環境或專門元件将其所依賴的服務類對象的引用傳遞給它。也可以說,依賴被注入到對象中。<b>是以,控制反轉是,關于一個對象如何擷取他所依賴的對象的引用,這個責任的反轉</b>。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

l  依賴注入使用以下三種基本技術:

n  類型1 (基于接口): 可服務的對象需要實作一個專門的接口,該接口提供了一個對象,可以從用這個對象查找依賴(其它服務)。

n  類型2 (基于setter): 通過屬性的setter方法為可服務對象指定服務。

n  類型3 (基于構造函數): 通過構造函數的參數為可服務對象指定服務。

不要重複發明輪子!

對于應用頻繁的需求,總是有人設計各種通用架構和類庫以減輕人們的開發負擔。例如,資料持久化是非常頻繁的需求,于是各種orm架構應運而生;再如,對mvc的需求催生了struts等一批用來實作mvc的架構。

随着依賴注入變成了非常頻繁的需求,而如果全部手工完成,不但負擔太重,而且還容易出錯。再加上反射機制的發明,于是,自然有人開始設計開發各種用于依賴注入的專用架構。這些專門用于實作依賴注入功能的元件或架構,就是ioc container。

ioc關注服務(或應用程式部件)是<b>如何定義的</b>以及<b>他們應該如何定位他們依賴的其它服務</b>。是以通常,通過一個<b>容器或定位架構</b>(著名的spring容器、)來獲得定義和定位的分離,容器或定位架構負責:

l  儲存可用服務的集合

l  提供一種方式将各種部件與它們依賴的服務綁定在一起

l  為應用程式代碼提供一種方式來請求已配置的對象(例如,一個所有依賴都滿足的對象), 這種方式可以確定該對象需要的所有相關的服務都可用。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

swiftsuspenders 支援三種類型的依賴注入:

ü  屬性(域)注入

ü  參數(方法/設值) 注入

ü  構造注入

我們将特别介紹屬性注入,以及在 robotlegs 裡如何使用。将屬性注入類有兩種選擇,你可以使用未命名,或命名的注入:

<b>[inject]</b>

<b>public var mydependency</b><b>:depedency; //</b><b>未命名注入</b>

<b>[inject(name="mynameddependency")]</b>

<b>public var mynameddependency</b><b>:nameddepedency; //</b><b>命名注入</b>

robotlegs裡三處提供了注入映射:mediatormap、commandmap、直接通過injector。mediatormap、commandmap也都是使用injector,但它們同時做了一些各自層(tier)所需要的額外工作。顧名思義,mediatormap用來映射mediator;commandmap用來映射command;其它所有需要被注入的内容 (包括但不限于 model) 都要直接使用 injector 映射。

具體 injector 類的擴充卡都遵照 iinjector 接口。 這個接口為不同的依賴注入解決方案提供了統一的api。 本文專注于 swiftsuspenders,但這些文法同樣适應于其它任何遵照 iinjector 接口的 injector。

injector是你應用程式裡所發生的所有依賴注入的生産工廠中的房間。它用來注入架構 actor,同時也可以用來執行你的應用程式所需要的任何其它注入。這包括但不限于 remoteobjects,httpservices,工廠類,或者事實上任何有可能成為你的對象所需要的依賴的類/接口。

下面是實作 iinjector 接口的類所提供的四個映射方法:

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

mediatormap 實作 imediatormap 接口。 imediatormap 提供兩個方法來将你的 mediators 映射到 view 并注冊它們以便用來注入。

<b>mapview(viewclassorname</b><b>:*</b><b>,mediatorclass</b><b>:class</b><b>,injectviewas</b><b>:class = null</b><b>,autocreate</b><b>:boolean = true</b><b>,autoremove</b><b>:boolean = true)</b><b>:void</b>

mapview 接受一個視圖類,myawesomewidget,或者一個視圖的類全名,com.me.app.view.components::myawesomewidget 作為第一個參數。 第二個參數是将要作為視圖元件中介的 mediator 類。 [injectviewas 内容未完成],最後的兩個參數 autocreate 和 autoremove 提供友善的自動管理 mediator 的布爾值開關。

//在你的程式裡某個映射/配置發生的地方

<b>mediatormap.mapview(myawesomewidget</b><b>,myawesomewidgetmediator); </b>

//在conntextview 的顯示清單裡的某個地方

<b>var myawesomewidget:myawesomewidget = new myawesomewidget();</b>

this.addchild(myawesomewidget); // added_to_stage 事件被抛出,觸發這個視圖元件的中介機制

這個方法使用了自動中介機制。

commandmap 類實作 icommandmap 接口,提供一個用來将 command 映射到到觸發它們的架構事件的方法。

<b>mapevent(eventtype</b><b>:string</b><b>,commandclass</b><b>:class</b><b>,eventclass</b><b>:class = null</b><b>,oneshot</b><b>:boolean = false)</b>

你要提供給 commandmap 一個可以執行的類,執行它的事件類型,可選的這個事件的強類型,以及這個 command 是否隻被執行一次并且随即取消映射的布爾值開關。

這個可選的強類型事件類用來對flash平台的"magic string"事件類型系統做額外的保護。以避免采用相同僚件類型字元串的不同僚件類之間的沖突。

<b>commandmap.mapevent(myappdataevent</b><b>。data_was_received</b><b>,mycoolcommand</b><b>,myappdataevent); </b>

//在事件被廣播的另外一個架構actor裡

//這觸發了随後被執行的被映射的 command

dispatch(new myappdataevent(myappdataevent.data_was_received,sometypedpayload))

robotlegs提供了一個比較規範的mvc+s(model模型,view視圖,controller控件和service服務)實作,來幫助開展工作。通過将幾個經過時間檢驗的設計模式整合到一個具體實作, robotlegs 的 mvcs 實作可以用做建立你的應用程式的一緻方案。 通過這些架構概念着手一個應用程式, 你甚至可以在開始你的設計之前避免很多常見的障礙:

ü  分離:mvcs 提供一種将你的應用程式分離到提供特定功能的無關聯的層的很自然的方法。 view 層處理使用者互動。 model 層處理使用者建立的或從外部擷取的資料。 controller 提供一種封裝各層之間複雜互動的機制。 最後, service 層提供一種和外界(比如遠端服務 api 或檔案系統)互動的獨立機制。

ü  組

織:通過這種分離我們自然獲得一個組織水準。 每個項目都需要某個組織水準。

是的,有人可以把他們所有的類都扔到頂級包下完事,但即使是最小的項目這也是不可接受的。 當一個項目有了一定的規模就需要開始組織類檔案的結構了。

當向同一個應用程式開發中增加團隊成員的時候問題就更加嚴重了。 robotlegs 的 mvcs 實作為項目描繪出一個分為四層的優雅的組織結構。

ü  解耦:robotlegs 的mvcs實作将應用程式解耦為4層。 每層都與其它層隔離, 使分離類群組件分别測試變得非常容易。除了簡化測試程序, 通常也使類更具便攜性以在其它項目中使用。 比如, 一個連接配接到遠端 api 的 service 類可能在多個項目中都很有用。 通過解耦這個類, 它可以不需重構便從一個項目轉移到另一個中使用。

一個典型的robotlegs mvc+s應用程式包含以下幾個部分:

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

ü  <b>context</b>:所謂context(上下文),實際上是一套自展機制,用來初始化robotlegs所使用的依賴注入以及各種核心工具。

ü  <b>commands</b>:所謂commands(指令),代表的是應用程式所能執行的獨立操作。通常,commands(指令)會作為對使用者操作的反應,但指令的作用并不僅限于此。

ü  <b>mediators</b>:所謂mediators(中介),是用來管理應用程式中的視圖元件與應用程式中的其它對象之間的資訊交流。

ü  <b>model</b><b>:</b>models(模型)中儲存着資料資訊,并且表現出應用程式目前的狀态。

ü  <b>service</b>:services(服務),是應用程式與外界的接口。

下面用用互操作view到得到響應的一個流程圖:

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

robotlegs代碼包結構組織:

[<b>domain.lib</b>]

    various utilities

[<b>domain.project</b>]

    [projectmodule]

        [<b>model</b>]

            [events]

            [vo]

            projectmodulestatemodel

        [<b>view</b>]

            [renderers]

            [skins]

            myprojectmoduleview

            myprojectmoduleviewmediator

        [<b>controller</b>]

            [startup]

            myprojectmoduleactioncommand

        [<b>service</b>]

            [helpers]

            myprojectmoduleservice

            iprojectmoduleservice

        [<b>signals</b>]

        [model]

        [view]

            [skins]

        [controller]

        [service]

            iprojectmoduleservice

        [signals]

    …

這是joel hooks建議的包結構。這是一個多子產品情況的包結構,如果是單子產品,可以少去projectmodule這一層。[signals]包不是必須的,除非你用到了signals。

把每個子產品要都用到的公共代碼放到[domain.lib]下。子產品和子產品内代碼保證獨立,不會互相使用(引用,執行個體化)。

startupcommand内代碼建議以mvc結構分離。如果一個子產品中startupcommnad内有過多代碼,建議把它拆分成modelstartupcommand,controllerstartupcommand和viewstartupcommand,這樣職責更清晰。

[controller]和[view]中,如果有很多類,建議按照功能建立子目錄。

實際上是一套自展機制,用來初始化robotlegs所使用的依賴注入以及各種核心工具,一個應用程式是可以有多個 context 的,這對想要加載外部子產品的應用程式很有用,因為在一個 context 裡的 actor 隻能在他們的 context 定義的範圍之内互相通訊,是以在一個子產品化的應用程式裡,不同context 之間的通訊是完全可能的。

每一個robotlegs項目都以context開始,隻有context執行個體化之後,robotlegs才能啟動和運作。建立context需要給提供一個根視圖并調用startup()方法。

每個rogotlegs應用程式需要一個根視圖——displayobjectcontainter的一個執行個體。它将供mediatormap使用,是以當子視view圖添加到根視圖時,對應的mediator會被建立并和view關聯起來。

啟動應用程式需要在所有配置都準備好之後,然後調用startup()方法來啟動。可以通過将autostartup:boolean=true,然後該方法會自動被調用;又或者将autostartup:boolean=false,然後手動調用startup()方法。

在startup()方法中會初始化依賴注入規則!如果規則很少,可以全部寫在這個該方法中;否則,建議分離到不同的配置類中。

controller 層由 command 類展現(一個command是一個簡明、單一目的的控制器controller對象)。command是短生命周期的無狀态對象。它們在被執行個體化和執行之後立即釋放。command 應該隻在處理架構事件時被執行,而不應該被任何其他架構 actor 執行個體化或執行。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

command 用于應用程式各層之間互相通訊,也可能用來發送系統事件。這些系統事件既可能發動其它的 command, 也可能被一個 mediator 接收,然後對一個 view component 進行對應這個事件的工作。

command 被 context 的 commandmap 注冊到 context。commandmap 在 context 和 command 類裡預設可用。command 類被注冊到 context 時接收4個參數: 一個事件類型; 響應這個事件時執行的 command 類; 可選的事件類; 一個是否該 command 隻被執行一次随即被取消注冊而不響應後續事件觸發的一次性設定.

command 被 mediators,services,models,和其它 command 廣播的架構事件觸發。一個被映射的 command 在響應一個架構事件時被執行個體化,所有已被映射,并被 [inject] 中繼資料标簽标記過的依賴都會被注入到這個 command。另外,觸發這個 command 的事件執行個體也會被注入。當這些依賴被注入完畢,command 的執行方法會被自動調用,command 便會進行它的工作。你不需要,而且不應該直接調用 execute() 方法。這是架構的工作。

command 是解耦一個應用程式裡各個 actor 的非常有用的機制。因為一個 command 永遠不會被 mediator,model 或者 service 執行個體化或執行,這些類也就不會被耦合到 command,甚至都不知道 command 的存在.

為了履行它們的職責,command 可能:

ü  映射 mediator,model,service,或者 context 裡的其它 command

ü  廣播可能被 mediator 接收或者觸發其它 command 的事件.

ü  被注入model,service,和mediator 以直接進行工作.

需要注意的是,不建議在一個 command 裡直接和 mediator 互動。雖然這是可行的,但會将這個 mediator 耦合到這個 command。因為 mediator 不像 service 和 model,它可以接受系統事件,更好的做法是讓 command 廣播事件,然後讓需要響應這些事件的 mediator 監聽它們。

view 由 mediator 類展現。繼承 mediator 的類管理應用程式中的 view component 與應用程式中的其它對象之間的資訊交流。一個mediator 将會監聽架構事件和 view component 事件,并在處理所負責的 view component 發出的事件時發送架構事件。這樣開發者可以将應用程式特有的邏輯放到 mediator,而避免把 view component 耦合到特定的應用程式。

注意,<b>mediator僅僅是架構和view component之間的橋梁,這也是他唯一的職責。</b>

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

一個 view component 是任何的ui元件和/或它的子元件。一個 view component 是已被封裝的,盡可能多地處理自己的狀态和操作。一個 view component 提供一個包含了事件,簡單方法和屬性的api。mediators負責代表它所中介的view component和架構互動。這包括監聽元件及其子元件的事件,調用其方法,和讀取/設定元件的屬性.

一個 mediator 監聽它的 view component 的事件,通過 view component 暴露的 api 通路其資料。一個 mediators 通過響應其它架構 actor 的事件并對自己的 view component 進行相應修改來代表它們。一個 mediator 通過轉發 view component 的事件或自己向架構廣播合适的事件來通知其它的架構 actor.

任何可以通路到mediatormap執行個體的類都可以映射 mediator。這包括 mediator,context,和 command 類.

這是映射一個 mediator 的文法:

<b>mediatormap.mapview( viewclass</b><b>,mediatorclass</b><b>,autocreate</b><b>,autoremove );</b>

當view添加到舞台上時,mediator會被自動建立并關聯起來。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

當view從舞台上移除時,mediator會被自動清除。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

當一個 view component 在一個 context 的 contextview 裡被添加到舞台上的時候,它預設地會被根據 mediatormap 做映射時的配置被自動關聯。在一個基本的 mediator 裡,viewcomponent會被注入為被中介的 view component。一個 mediator 的viewcomponent屬性是 object 類型的。在大多數情況下,我們希望通路一個強類型的對象以從中獲益。為此目的,我們注入被中介的 view component 的強類型執行個體:

public class gallerylabelmediator extends mediator implements imediator

{

      [inject]

      public var mycustomcomponent:mycustomcomponent;

      /**

      * 覆寫 onregister 是添加此 mediator 關心的任何系統或 view component 事件的好機會.

      */

      override public function onregister():void

      {

             //添加一個事件監聽器到 context 來監聽架構事件

             eventmap.maplistener( eventdispatcher,mycustomevent.do_stuff,handledostuff );

             //添加一個事件監聽器到被中介的 view component

             eventmap.maplistener( mycustomcomponent,mycustomevent.did_some_stuff,handledidsomestuff)

      }

      protected function handledostuff(event:mycustomevent):void

             //把事件的強類型負載設定到 view component 的屬性。

             //view component 很可能基于這個新資料管理自己的狀态.

             mycustomcomponent.aproperty = event.payload

      protected function handledidsomestuff(event:mycustomevent):void

             //把這個事件轉發到架構

             dispatch(event)

}

通過這種方法我們現在可以很友善地通路被中介的 view component 的公開屬性和方法.

事件監聽器是 mediator 的眼睛和鼻子。因為架構内的所有通訊都通過原生的flash事件,mediator 可以通過添加事件監聽器來響應感興趣的事件。除了架構事件,mediator同時監聽所中介的 view component 的事件.

通常在 mediator 的 onregister 方法裡添加事件監聽。在 mediator 生命周期中的這個階段,它已經被注冊并且它的 view component 和其它依賴也都已被注入。具體的 mediator 類必須覆寫 onregister 方法。也可以在其它方法裡添加事件監聽,比如響應架構事件和 view component 事件的事件處理方法裡.

mediators 裝備了一個有 maplistener() 方法的 eventmap。這個方法注冊每個被添加到 mediator 的事件監聽,并且確定 mediator 被架構取消注冊時删除這些事件監聽。flash 裡删除事件監聽是很重要的,因為如果一個類裡添加了事件監聽而沒有删除,player将無法對此類進行運作時垃圾回收(gc,garbage collection)。也可以使用傳統的 flash 文法添加事件監聽器,但要注意也要手動把它們删除。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

所有架構裡的actor在執行個體化時都會被注入一個eventdispatcher屬性。這個eventdispatcher就是 mediator 發送和接受架構事件的機制.

<b>eventmap.maplistener(eventdispatcher</b><b>,someevent.it_is_important</b><b>,handleframeworkevent)</b>

通過此文法,一個 mediator 現在監聽了someevent.it_is_important事件并在handleframeworkevent方法裡處理它。

mediator的一個很重要的職責就是向架構發送其它 actor 可能感興趣的事件。這些事件通常是在響應應用程式使用者和被中介的 view component 之間的一些互動時發出的。這裡同樣有一個可以減少發送事件到架構的代碼輸入的很有用的方法:

<b>dispatch(new someevent(someevent.you_will_want_this</b><b>,myviewcomponent.somedata))</b>

這個事件現在可以被其它 mediator 接收或者執行一個 command 了。發出事件的 mediator 并不關心其它的 actor 如何回應這個事件,它隻是簡單地廣播一條有事發生的消息。一個 mediator 也可以監聽自己發出的事件,然後據此作出回應.

mediator 負責所中介的 view component 發出的事件。這可以是個獨立元件,比如 textfield 或者 button,也可以是有嵌套層級的複雜元件。當 mediator 收到 view component 發出的事件會使用指定的方法處理它。和架構事件一樣,eventmap 的 maplistener 方法是給一個 mediator 添加事件監聽的首選.

<b>eventmap.maplistener(mymediatedviewcomponent</b><b>,someevent.user_did_something</b><b>,handleuserdidsomethingevent)</b>

響應一個 view component 的事件時,一個 mediator 可能:

ü  考察 view component 的目前狀态

ü  對view component 進行需要的工作

ü  發送系統事件以通知其它actor有事發生

你的 mediator 可以監聽 service 和 model 類派出的系統事件來提高松耦合性。通過監聽事件,你的 mediator 不需要關心事件來源,而隻需直接使用事件攜帶的強類型的負載payload資料。是以,多個 mediator 可以監聽相同的事件然後根據所收到的資料調整自己的狀态.

在一個 mediator 裡直接通路 service 可以提供很大便利而不會帶來嚴重的耦合性問題。一個 service 并不存儲資料,隻是簡單地提供一個向外部service發送請求并接受響應的api。能夠直接通路這個api可以避免在你的應用程式中增加不需要的 command 類來達到同樣目的。如果這個 service api 在很多 mediator 中通過相同的方式通路,将此行為封裝到一個 command 裡有益于保持此行為的一緻性并減少對此 service 的反複調用以及在你的 mediator 裡的直接通路.

建議通過 model 和 service 實作的接口将 model 和 service 注入 mediator。

通路其它 mediator

如同 service 和 model,在一個 mediator 裡也可以注入和通路其它的 mediator。這種做法是 強烈不建議的 因為這種緊耦合可以簡單地通過使用架構事件進行通訊而避免。

model 類用來管理對應用程式的資料模型的通路。model 為其它架構actor提供一個 api 來通路,操作和更新應用程式資料。這個資料包括但不限于原生資料類型比如 string,array,或者像 arraycollection 一樣的域特有對象或集合.

model 有時被當做簡單的 model 比如 usermodel,有時也被當做 proxy 比如 userproxy。在 robotlegs 裡,這兩種命名都是用作相同的目的,為應用程式資料提供一個 api。不管采用哪種命名 model 都繼承提供了核心架構依賴和一些有用方法的 actor 基類。

model 會在對資料模型進行某些工作之後發出事件通知。model 通常具有極高的便攜性。

model類封裝了應用程式資料模型并為其提供一個 api。一個 model 類是你的應用程式資料的看門人。應用程式裡的其它 actor 通過 model 提供的 api 請求資料。因為資料是通過 model 更新,model 裝備了向架構廣播事件的機制以向其它 actor 通知資料模型的變化使它們得以據此調整自己的狀态.

除了控制對資料模型的通路,model 通常也被用來保證資料狀态的有效性。這包括對資料進行計算,或域特有邏輯的其它領域。model 的這個職責非常重要。model 是應用程式中最有潛力具有便攜性的層。通過把域邏輯放入 model,以後的 model 實作就不再需要像把域邏輯放入 view 或 controller 層那樣重複這些相同的邏輯,作為一個例子,你的 model 裡可能執行購物車資料的計算。一個 command 将會通路這個方法,最終的計算結果将會被作為被某個 mediator 監聽的事件派發出去。這個 mediator 将會根據這個被更新的資料更新自己的 view component,應用程式的第一個疊代是個典型的 flex 程式。這個計算也很容易在一個 mediator 甚至視圖裡進行。應用程式的第二個疊代是一個需要全新視圖元素的移動裝置 flash 應用程式。因為這個邏輯在 model 裡,是以可以很容易被兩個完全不同元素的視圖複用.

injector 有幾個方法可以用來将你的 model 類映射到你的架構actor。另外,這些方法事實上可以用來注入任何類到你的類裡.

将一個已存在的執行個體當做一個單例注入映射,使用下面的文法:

i<b>njector.mapvalue(mymodelclass</b><b>,mymodelclassinstance)</b>

為每個注入映射一個類的新執行個體,使用下面的文法:

<b>injector.mapclass(mymodelclass</b><b>,mymodelclass)</b>

另外,這也可以用來使用被注入的實作某接口的合适的類來映射這個用來注入的接口.

<b>injector.mapclass(imymodelclass</b><b>,mymodelclass)</b>

為某個接口或類映射一個單例執行個體,使用下面的文法:

<b>injector.mapsingleton(mymodelclass</b><b>,mymodelclass)</b>

需要注意重要的一點,當提及上面的一個單例時,它并不是一個單例模式的單例。在這個 context 之外并不強制它作為一個單例。injector 簡單地確定這個類的唯一一個執行個體被注入。這對處理你的應用程式資料模型的 model 非常重要.

model 類提供一個友善的dispatch方法用來發送架構事件:

<b>dispatch( new importantdataevent(importantdataevent.important_data_updated))</b>

有很多理由派發一個事件,包括但不限于:

ü  資料已被初始化并準備好被其它 actor 使用

ü  一些資料片被添加到 model

ü  資料被從 model 中删除

ü  資料已改變或者更新

ü  資料相關的狀态已改變

在一個 model 裡監聽架構事件

雖然技術上可能,但強烈不建議這樣做。不要這樣做。隻是為了說清楚:不要這樣做。如果你這樣做了,不要說你沒被警告過.

service 用來通路應用程式範圍之外的資源。這包括但當然不限于:

ü  web services

ü  檔案系統

ü  資料庫

ü  restful apis

ü  通過 localconnection 的其它 flash 應用程式

service 封裝了這些和外部實體的互動,并管理這個互動産生的 result ,fault 或其它事件.

你可能注意到 service 和 model 的基類非常相像。事實上,你可能注意到除了類名,它們其實是一樣的。那麼為什麼用兩個類呢? model 和 service 類在一個應用程式裡有完全不同的職責。這些類的具體實作将不再相像。如果沒有這個分離,你将經常發現 model 類在通路外部服務。這讓 model 有很多職責,通路外部資料,解析結果,處理失敗,管理應用程式資料狀态,為資料提供一個 api,為外部服務提供一個 api,等等。通過分離這些層有助于緩解這個問題。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

一個 service 類為你的應用程式提供一個和外部服務互動的 api。一個 service 類将連接配接外部服務并管理它收到的響應。service 類通常是無狀态的實體。他們并不存儲從外部服務收到的資料,而是發送架構事件來讓合适的架構 actor 管理響應資料和失敗.

有injector 的多個可用的方法可以用來映射你的 service 類以注入你的其它架構 actor。另外,這些方法也可以用來注入事實上任何類到你的類裡。

<b>injector.mapvalue(myserviceclass</b><b>,myserviceclassinstance)</b>

為每個注入映射一個類的新執行個體,使用下面的文法:

<b>injector.mapclass(myserviceclass</b><b>,myserviceclass)</b>

<b>injector.mapclass(imyserviceclass</b><b>,myserviceclass)</b>

為某個接口或類映射一個單例執行個體,使用下面的文法:

<b>injector.mapsingleton(myserviceclass</b><b>,myserviceclass)</b>

需要注意重要的一點,當提及上面的一個單例時,它并不是一個單例模式的單例。在這個 context 之外并不強制它作為一個單例。injector 簡單地確定這個類的唯一一個執行個體被注入.

在一個 service 裡監聽架構事件

雖然技術上可能,但 強烈不建議 這樣做。不要這樣做。隻是為了說清楚: 不要這樣做。如果你這樣做了,不要說你沒被警告過.

service 類提供一個友善的dispatch方法用來發送架構事件:

<b>dispatch( new importantserviceevent(importantserviceevent.important_service_event))</b>

從外部擷取到的資料并不符合我們應用程式的 context。它們是外來者。可以圍繞外部資料類型對應用程式進行模組化,或者更可取地,轉換這些資料以符合應用程式。應用程式裡有兩處可以進行這項操作/轉換。service 和 model 都很适合。<b>service </b><b>是進入外部資料的第一個點,是以它是操作一個外部服務傳回的資料的更好的選擇。</b>外來資料應該在第一個機會轉換到應用程式域。

提供一個使用工廠類而不是在 service 裡生成應用程式域對象的例子… 适當的

當資料被轉換為應用程式域特有的對象之後發出帶有強類型負載的事件以被對此關心的 actor 立即使用.

service 組合的最後一個部分是自定義事件。沒有事件的 service 隻是啞巴。他們可能做的任何工作都不會被其它架構成員注意到。一個 service 将會使用自定義事件來向應用程式發出聲音。事件并不一定是唯一的意圖。如果這個 service 正在轉換資料它可以使用一個普通的事件來派發強類型的資料給感興趣的應用程式 actor。

l  robotlegs配合as3signal使用,替代flash原生事件機制。采用as3signal可以有效減少view-mediator的事件對象,其效率高于事件機制。

when an event (signal) is dispatched but nothing is listening for it:

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

when an event (signal) is dispatched and handled by one method listener:

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

n  盡量将子產品内事件和子產品間的事件分開,不要混雜着用,用于區分它們。

n  所有需要公用的對象或類(vo,model,service)都在主子產品的startup時注入,這樣子子產品都可以很友善的用到。

flash開發架構:RobotLegs 1.  MVC 2.  RobotLegs與其它架構的比較 3.  RobotLegs的依賴注入 4.  Robotlegs的标準MVCS實作 5.  擴充點

l  在添加大量sprite到舞台前,可以設定:mediatormap.enabled=false;。完成後再設定為true,這樣可以避免mediatormap偵聽到added_to_stage事件後頻繁進行不必要的操作。也可以使用robotlegs 的 lazymediator 擴充。

<b>如何使用</b>

n  在 context 裡 override mediatormap 的 getter 方法:

return _mediatormap || (_mediatormap = <b>new</b> lazymediatormap(contextview, injector));

n  在 view 類的構造函數裡增加:

<b>new</b> lazymediatoractivator(this);

<b>作用</b>

n  lazymediatormap 不監聽顯示清單裡所有的 added_to_stage 事件而檢測所有被添加到顯示清單的顯示對象。

<b>如何工作</b>

n  當 view 被添加到 stage 或從 stage 移除時 lazymediatoractivator 廣播 lazymediatorevent。

n  lazymediatormap 監聽 context 的 lazymediatorevent 然後檢查對應的 view。