Robotlegs是一種純AS3類型的微架構,其可以將應用程式各層排布在一起,主要套用於Flash、Flex和 AIR等軟體上。
基本介紹
- 外文名:Robotlegs
- 類型:純 AS3 微架構
- 套用軟體:Flash, Flex, 和 AIR
- 機制:將應用程式各層排布在一起
Robotlegs,依賴注入,使用 Injectors,SwiftSuspenders 適配器注入語法,Injector 類的映射注入,MediatorMap 類的依賴注入,CommandMap 類的依賴注入,The Context,MVCS參考實現,Context,Controller & Commands,View & Mediators,Model, Service and the Actor,框架事件,
Robotlegs
Robotlegs 是一個用來開發Flash, Flex, 和 AIR套用的純 AS3 微架構(框架). Robotlegs 專注於將應用程式各層排布在一起並提供它們相互通訊的機制. Robotlegs 試圖通過提供一種解決常見開發問題的經過時間檢驗的架構解決方案來加速開發. Robotlegs 無意鎖定你到框架, 你的類就是你的類的樣子, 而且應該很容易地切換到其他框架.
框架提供一個基於 Model-View-Controller元設計模式的默認實現. 這個實現提供一個針對應用程式結構和設計的強烈建議. 雖然它確實輕微減低了你的應用程式的便攜性, 不過它依然以最低限度影響你的具體類為目標. 通過擴展 MVCS實現類, 你可以獲得很多有用的方法和屬性.
你不必使用Robotlegs的標準 MVCS實現.你可以使用它的任意部分, 或者完全不使用它, 或者使用自己的實現來適應你的需求. 它是為了提供合適的參考實現和快速開始使用 Robotlegs 而被包含進來。
依賴注入
Robotlegs 圍繞 依賴注入設計模式展開.
最簡單地, 依賴注入是為對象提供實例變數或屬性的行為. 當你傳遞一個變數到一個類的構造函式, 你在使用依賴注入. 當你設定一個類的屬性, 你在使用依賴注入. 如果你不是使用嚴格的過程或線性方式編寫AS3, 很可能你現在就在使用依賴注入。
Robotlegs 使用基於元數據的自動依賴注入. 這是為了方便開發而提供, 而且在排布應用程式並提供類和它所需要的依賴時,可以減少很多代碼量. 雖然完全可以手動提供這些依賴, 但是允許框架來履行這些職責可以減少出錯的機會,並且通常可以加快編碼進程。.
使用 Injectors
Robotlegs 採用一種適配器(adapter)機制來為框架提供依賴注入機制. 默認地, 框架配備了 SwiftSuspenders注入/反射庫來適合這個要求. 另有 SmartyPants-IoC 和 Spring Actionscript 的適配器可以使用. 可能有潛在的特定需求來使用其它的依賴注入適配器, 但是如果沒有特別的理由, 建議使用默認的 SwiftSuspenders, 因為它為 Robotlegs 做了一些特別調整.
SwiftSuspenders 適配器注入語法
SwiftSuspenders 支持三種類型的依賴注入:屬性(域)注入、參數(方法/設值)和 注入構造注入。
這裡我們將特別介紹屬性注入, 以及在 Robotlegs 里如何使用. 將屬性注入類有兩種選擇. 你可以使用未命名,或命名的注入:
[Inject]
public var myDependency:Depedency; //未命名注入[Inject(name="myNamedDependency")]
public var myNamedDependency:NamedDepedency; //命名注入
Robotlegs 里三處提供了注入映射. MediatorMap, CommandMap, 和直接通過 Injector . MediatorMap 和 CommandMap 也都是使用 Injector, 但它們同時做了一些各自層(tier)所需要的額外工作. 顧名思義, MediatorMap 用來映射 Mediator, CommandMap 用來映射 Command, 其它所有需要被注入的內容 (包括但不限於 Model) 都要直接使用 Injector 映射.
Injector 類的映射注入
具體 Injector 類的適配器都遵照 IInjector 接口. 這個接口為不同的依賴注入解決方案提供了統一的API. 本文檔專注於 SwiftSuspenders, 但這些語法同樣適應於其它任何遵照 Iinjector 接口的 Injector.
injector是你應用程式里所發生的所有依賴注入的生產車間. 它用來注入框架 actor, 同時也可以用來執行你的應用程式所需要的任何其它注入. 這包括但不限於 RemoteObjects, HTTPServices, 工廠類, 或者事實上任何有可能成為你的對象所需要的依賴的類/接口.
下面是實現 IInjector 接口的類所提供的四個映射方法:
mapValue
mapValue 用來映射一個對象的特定實例到一個 injector. 當請求一個特定的類,使用類的這個特定實例來注入.
//你的應用程式中某個映射/配置發生的地方
var myClassInstance:MyClass = new MyClass();
injector.mapValue(MyClass, myClassInstance);//在接收注入的類中
[Inject]
public var myClassInstance:MyClassmapValue(whenAskedFor:Class, instantiateClass:Class, named:String = null)
MyClass 的實例被創建和保留,並在被請求的時候被注入. 當此類被請求的時候,這個實例被用來滿足這個注入請求. 請注意很重要的一點,因為你已經手動創建並通過 mapValue 映射了一個類實例, 這個實例所需要的依賴將不會被自動注入. 你需要手動或通過 injector 注入這些依賴:
injector.injectInto(myClassInstance);
這將立即為此實例提供已映射的可以注入的屬性。.
mapClass
mapClass 為每一個注入請求提供這個被映射的類的一個 特有( unique) 實例.
//你的應用程式中某個映射/配置發生的地方
injector.mapClass(MyClass);//在第一個接收注入的類里
[Inject]
public var myClassInstance:MyClass//在第二個接收注入的類里
[Inject]
public var myClassInstance:MyClass
為上面的每一個注入提供MyClass的 特有( unique) 實例來完成請求.
mapClass(whenAskedFor:Class, named:String = null)
injector 提供了一個方法來實例化被映射的對象:
injector.mapClass(MyClass);
var myClassInstance:MyClass = injector.instantiate(MyClass);
這提供你的對象的一個實例,並填充了此對象包含的所有被映射的注入點(injection points).
mapSingleton
mapSingleton 為每一個注入請求提供類的一個 單一_(_single) 實例. 為所有映射提供類的單一實例確保你維護一個一致的狀態並且不用擔心創建被此類的多餘實例. 這是一個被框架強制和管理的單一實例, 而不是一個在類內部強制的單例(Singleton).
//你的應用程式中某個映射/配置發生的地方
injector.mapSingleton(MyClass);//在第一個接收注入的類里
[Inject]
public var myClassInstance:MyClass//在第二個接收注入的類里
[Inject]
public var myClassInstance:MyClass
在上面的例子裡, 兩個注入請求都將由被請求類的相同實例填充. 這個注入是被延遲的, 即對象直到第一次被請求才被實例化.
mapSingletonOf(whenAskedFor:Class, useSingletonOf:Class, named:String = null)mapSingletonOf
mapSingletonOf在功能上非常像 mapSingleton. 它對映射抽象類和接口很有用, 而 mapSingleton 用來映射具體類實現.
//你的應用程式中某個映射/配置發生的地方
injector.mapSingletonOf(IMyClass, MyClass); //MyClass implements IMyClass//在第一個接收注入的類里
[Inject]
public var myClassInstance:IMyClass//在第二個接收注入的類里
[Inject]
public var myClassInstance:IMyClass
這個注入方法對創建使用多態的更具可測性的類非常有用. 在下面的 Service 實例章節可以找到一個例子.
MediatorMap 類的依賴注入
MediatorMap 實現 IMediatorMap 接口. IMediatorMap 提供兩個方法來將你的 mediators 映射到 view 並註冊它們以便用來注入.
mapView(viewClassOrName:*, mediatorClass:Class, injectViewAs:Class = null, autoCreate:Boolean = true, autoRemove:Boolean = true):void
mapView接受一個視圖類, MyAwesomeWidget, 或者一個視圖的類全名, com.me.app.view.components::MyAwesomeWidget作為第一個參數. 第二個參數是將要作為視圖組件中介的 Mediator 類. [injectViewAs 內容未完成], 最後的兩個參數 autoCreate 和 autoRemove 提供方便的自動管理 mediator 的布爾值開關.
//在你的程式里某個映射/配置發生的地方
mediatorMap.mapView(MyAwesomeWidget, MyAwesomeWidgetMediator);//在conntextView 的顯示列表里的某個地方
var myAwesomeWidget:MyAwesomeWidget = new MyAwesomeWidget();
this.addChild(myAwesomeWidget); // ADDED_TO_STAGE 事件被拋出, 觸發這個視圖組件的中介機制
這個方法使用了自動中介機制. 手動中介,以及對此方面更深入的內容將稍後在 Mediators章節中介紹.
CommandMap 類的依賴注入
CommandMap 類實現 ICommandMap 接口, 提供一個用來將 command 映射到到觸發它們的框架事件的方法.
mapEvent(eventType:String, commandClass:Class, eventClass:Class = null, oneshot:Boolean = false)
你要提供給 commandMap 一個可以執行的類, 執行它的事件類型, 可選的這個事件的強類型, 以及這個 command 是否只被執行一次並且隨即取消映射的布爾值開關.
這個可選的強類型事件類用來對Flash平台的"magic string"事件類型系統做額外的保護.以避免採用相同事件類型字元串的不同事件類之間的衝突.
//在你的程式里某個映射/配置發生的地方
commandMap.mapEvent(MyAppDataEvent.DATA_WAS_RECEIVED, MyCoolCommand, MyAppDataEvent);//在事件被廣播的另外一個框架actor里
//這觸發了隨後被執行的被映射的 command
dispatch(new MyAppDataEvent(MyAppDataEvent.DATA_WAS_RECEIVED, someTypedPayload))
The Context
Context 是所有 Robotlegs 具體實現的中心. 一個 Context, 或者也許多個 Context, 提供其它層進行通訊的機制. 一個應用程式並非只能使用一個 Context, 但大多情況下一個 Context 就足夠了. 如果在 Flash 平台上創建模組化應用程式, 多個 Context 就是必須的了. Context 在一個應用程式里有三個功能: 提供初始化, [de-initialization – 非初始化?], 和用來通訊的事件中心bus.
package org.robotlegs.examples.bootstrap
{
import flash.display.DisplayObjectContainer;
import org.robotlegs.base.ContextEvent;
import org.robotlegs.core.IContext;
import org.robotlegs.mvcs.Context;
public class ExampleContext extends Context implements IContext
{
public function UnionChatContext(contextView:DisplayObjectContainer)
{
super(contextView);
}
override public function startup():void
{
//這個 Context 只映射一個 command 到 ContextEvent.STARTUP 事件.
//這個 StartupCommand 將映射其它將在應用程式里使用的的 command,
//mediator, service, 和 model.
commandMap.mapEvent( ContextEvent.STARTUP, StartupCommand, ContextEvent, true );
//啟動應用程式 (觸發 StartupCommand)
dispatch(new ContextEvent(ContextEvent.STARTUP));
}
}
}
MVCS參考實現
Robotlegs 裝備了一個參考實現. 這個實現遵照經典的 Model-View-Controller (MVC) 元設計模式, 另外增加了第四個叫做 Service 的 actor. 這些層在本文檔中通稱為"核心 actor", 或者簡稱為"actor".
MVCS提供一個應用程式的框架概況. 通過將幾個經過時間檢驗的設計模式整合到一個具體實現, Robotlegs 的 MVCS實現可以用做創建你的應用程式的一致方案. 通過這些架構概念著手一個應用程式, 你甚至可以在開始你的設計之前避免很多常見的障礙:分離 組織 解耦。
分離
MVCS提供一種將你的應用程式分離到提供特定功能的無關聯的層的很自然的方法. view 層處理用戶互動. model 層處理用戶創建的或從外部獲取的數據. controller 提供一種封裝各層之間複雜互動的機制. 最後, service 層提供一種和外界(比如遠程服務 API或檔案系統)互動的獨立機制.
組織
通過這種分離我們自然獲得一個組織水平. 每個項目都需要某個組織水平. 是的, 有人可以把他們所有的類都扔到頂級包下完事, 但即使是最小的項目這也是不可接受的. 當一個項目有了一定的規模就需要開始組織類檔案的結構了. 當向同一個應用程式開發中增加團隊成員的時候問題就更加嚴重了. RobotLegs 的 MVCS實現為項目描繪出一個分為四層的優雅的組織結構.
解耦
Robotlegs 的MVCS實現將應用程式解耦為4層. 每層都與其它層隔離, 使分離類和組件分別測試變得非常容易. 除了簡化測試進程, 通常也使類更具便攜性以在其它項目中使用. 比如, 一個連線到遠程 API的 Service 類可能在多個項目中都很有用. 通過解耦這個類, 它可以不需重構便從一個項目轉移到另一個中使用.
這個默認實現只是充作最佳實踐建議的一個例子. Robotlegs 並不打算以任何方式束縛你到這個例子, 它只是一個建議. 你可以隨意開發自己的實現來適應你喜歡的命名規範和開發需求. 如果這正是你所追求的, 請一定告訴我們, 因為我們一直對新方案很感興趣, 而且它有可能作為一種替代實現包含到 RobotLegs 的代碼倉庫中.
Context
像 RobotLegs 中的其它實現一樣, MVCS實現也是圍繞一個或多個 Context. 這個 context 提供一個中心的事件 bus 並且處理自己的啟動和關閉. 一個 context 定義了一個範圍. 框架 actor 們處在 context 之內,並且在 context 定義的範圍之內進行相互間的通訊. 一個應用程式是可以有多個 context 的. 這對想要載入外部模組的應用程式很有用. 因為在一個 context 里的 actor 只能在他們的 context 定義的範圍之內相互通訊, 所以在一個模組化的應用程式里, 不同 context 之間的通訊是完全可能的.
本文檔不討論模組化編程的內容. 之後本文檔內所有提到的 Context 都指在一個應用程式里的單一的 context.
Controller & Commands
Controller 層由 Command 類體現. Command 是用來執行應用程式單一單位工作的, 無狀態的, 短生命周期的對象. Command 用於應用程式各層之間相互通訊, 也可能用來傳送系統事件. 這些系統事件既可能發動其它的 Command, 也可能被一個 Mediator 接收,然後對一個 View Component 進行對應這個事件的工作. Command 是封裝你的應用程式業務邏輯的絕佳場所.
View & Mediators
View 由 Mediator 類體現. 繼承 Mediator 的類用來處理框架和 View Component 之間的互動. 一個 Mediator 將會監聽框架事件和 View Component 事件, 並在處理所負責的 View Component 發出的事件時傳送框架事件. 這樣開發者可以將應用程式特有的邏輯放到 Mediator, 而避免把 View Component 耦合到特定的應用程式.
Model, Service and the Actor
MVCS架構里的 service 和 model 在概念上有著非常多的相似之處. 因為這種相似性, model 和 service 繼承了同樣的 Actor 基類. 繼承 Actor 基類可以獲得很多應用程式架構內的功能. 在 MVCS的 context 里, 我們通過利用繼承 Actor 基類來定義應用程式所需要用來管理數據以及和外界通訊的 model 和 service 類. 本文檔將把 model 和 service 類分別叫做 Model 和 Service.
澄清一點, 本文檔把體現應用程式四個層的所有類都稱為"framework actor"或"actor". 請不要和本例中包含的只被 Model 和 Service 類繼承的 MVCS類 Actor 混淆.
Model
Model 類用來在 model 層對數據進行封裝並為其提供 API. Model 會在對數據模型進行某些工作之後發出事件通知. Model 通常具有極高的便攜性.
Service
一個 service 層的 Service 用來和"外面的世界"進行通訊. Web service, 檔案存取, 或者其它任何應用程式範圍之外的行為對 service 類都很適合. Service 類在處理外部事件時會廣播系統事件. 一個 service 應該封裝和外部服務的互動且具有非常高的便攜性.
框架事件
Robotlegs 使用Flash的原生事件用於框架 actor 之間的通訊. 自定義事件類通常用於此用途, 雖然使用現有的 Flash 事件同樣可行. Robotlegs 不支持事件冒泡, 因為它並不依賴 Flash 顯示列表作為 event bus. 使用自定義類允許開發者通過給事件添加屬性來為框架 actor 之間通訊所用的系統事件提供強類型的負載.
所有的框架 actor 都可以傳送事件: Mediator, Service, Model, 和 Command. Mediator 是唯一接收框架事件的actor. Command 是在對框架事件的處理中被觸發. 一個事件既可以被一個 Mediator 接收, 也可以觸發一個 command.model 和 service 不應該監聽和處理事件. 這樣做會把它們緊耦合到應用程式特有邏輯而降低潛在的便攜性和復用性.