Skip to main content

[Flex] PureMVC standard with Spring extensions

由於上次稍微玩了一下 Robotlegs 依賴注入(DI) 主導的 MVC 框架,而著名也使用依賴注入的 Java / Java EE 的 Spring framework 出了 for ActionScript 的版本,剛好在最近 Spring ActionScript 1.0 正式 release 了(想了解 Spring 是啥咪東東的話請自行找 google 大神),這個版本除了基本框架外,也包含了 Cairngorm 與 PureMVC 的外掛...想當然耳,就拿來測試一下用在 PureMVC 內的感覺囉!!

參考了官方範例 中 PureMVC 唯二的範例原始檔,以下使用的是「設定檔依賴注入 facade 透過 addConfigSource() 的方式來 init 」:(其實除了 embed 外,都是外部載入)

Online Demo with source code

工作環境:FlashBuilder, Flex SDK4
  1. 請下載 PureMVC Standard 版本
  2. 再下載 Spring ActionScript 最新版本後,除了 spring-actionscript-cairngorm 不需要外,都放到 /src 下(記得只需要 org 開始...),也別忘了lib 內的 swc 檔 copy 到 /libs 下

Spring 的 injection 並不像 Robotlegs 直接來個 [Inject] metadata 的自動化那樣方便,但是其冷血度(檔案的鬆偶程度)更勝後者!如果你要使用設定檔(applicationContext.xml) 來做注入的話,準備工作就挺多的...XD
  1. 依照 applicationContext.xml 內設定的方式分別寫入 constructor 或者是 setter 依賴注入(本範例統一使用 setter injection)
  2. 為了跟大家都沒關係所以都使用 interface 來處理,所以你會在範例中發現大家都有介面...(並沒有真的研究過 Spring,也許還有其他作法)
  3. 準備 compiler 時候要用的 classe。由於在 setter, getter 的寫法上都使用 interface,所以真正用到的 class 需要預先在輸出階段就打包到程式內。
  4. 基本上 PureMVC 類 class 都改為繼承自 IocSimpleCommand, IocFacade, IcoMediator and IocProxy.


application-context.xml :
程式內用到的 Ioc 系列 class 的 getConfigName() 就是指 object tag id。

........
<object id="updateListCommand" class="com.mvc.control.UpdateListCommand">
<property name="listProxy" ref="listProxy"/>
</object>
<object id="listProxy" class="com.mvc.model.impl.ListProxy">
<property name="loaderDelegate" ref="loaderDelegate"/>
</object>
........


設定依賴注入的 setter name, ref 為 object tag 的 id。
其他 xml schemas 設定請看官網教學文件。
<property name="listProxy" ref="listProxy"/>

LoaderListCommand 實作:

........
public class UpdateListCommand extends IocSimpleCommand
{
private var m_proxy:IListProxy;
public function UpdateListCommand()
{
super();
}
// setter injection
public function set listProxy( proxy:IListProxy ):void{
m_proxy = proxy;
}
public function get listProxy():IListProxy{
return m_proxy;
}
...........

接下來在 compiler config 的 xml 中列出所有要預先打包的 classes:
configurationClassesCompilerConfig.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flex-config>
<includes>
<symbol>com.mvc.control.StartUpCommand</symbol>
<symbol>com.mvc.control.UpdateListCommand</symbol>
<symbol>com.mvc.view.ListMediator</symbol>
<symbol>com.mvc.model.impl.ListProxy</symbol>
<symbol>com.mvc.delegate.impl.LoaderDelegate</symbol>
</includes>
</flex-config>

然後:在 Project/properties 中設定 Additional Compiler Arguments:

-load-config+=config/configurationClassesCompilerConfig.xml

如下圖位置:

基本上的設定就是如同上面步驟。

最後,範例檔內有兩個外部 list data xml,你可以試著修改 application-context.xml 中的 serviceUrl value to "List2.xml"

<object id="loaderDelegate" class="com.mvc.delegate.impl.LoaderDelegate">
<property name="serviceUrl" value="List2.xml"/>
</object>

重新 reload 後你會發現,這時候 LoaderDelegate 所載入的資料就是 List2.xml 囉!如果你預先將同類可置換的 class 打包起來,你也可以在 runtime 的時候修改 application-context object class ref,這就是 Ioc 強大的地方囉!

結語:
以上僅說明到 PureMVC with Spring extensions 部分,其餘 Spring ActionScript Core API 請自行上官網學習囉!
BTW...對它不熟的朋友們請勿輕易服用拿真正的專案去實作捏...XD

Comments

  1. spring有一個基本假設,就是可以透過reflection動態載入程式碼,這在其他的主要程式語言(java, c#, 甚至 vb.net)都是成立的。

    但偏偏reflection是flash的弱項,另外就是寫loadee(被載入的程式碼檔案),需要手動exclude class到讓人瘋狂。所以,現在spring.actionscript使用的這些設定,都是為了能用一個.swf檔案把一切打包,但一開始,這就大大減損了spring的長處(使用config file動態決定程式碼的執行,程式碼散落在各個.dll檔案中,而非compile time就決定)。

    而且,我也懷疑在大型計畫下,一個必須用人工維護的20~30k config xml檔案,本身不會引入更多的錯誤。我個人關注過這個計畫很長一陣子(我這兩年都在用spring.net寫asp.net),這不是一個容易使用的library,再加上上面說的種種限制,也因此,我對這個專案一直持保留的態度。

    但我是建議大家可以藉這個機會瞭解dependency injection,或是直接看Martin Fowler當初提出這個概念的原文(中文版的連結已經失效很久了,但google應該還找得到):

    http://martinfowler.com/articles/injection.html

    .swf 檔案與avm,需要一些蠻基本的改變,才能跟spring相處愉快,但那很可能就改變了flash之所以為flash的基本假設:節省檔案大小,因此用不到的,就不會放進.swf檔案中。(silverlight就不是這樣想的,所以,稍微有一點規模的案子,就是一堆.xap檔案會被載入)

    後續會如何發展,倒是頗值得關注...

    ReplyDelete
  2. 拉丁大講的沒錯,Spring AS3 的版本實在有點麻煩,尤其光手動打包必要的東西這段就很麻煩了,我猜光一般專案那個 config xml 就應該會很可觀。如果真的需要用到 Spring 的話,程式碼就需要如同拉丁大所說的散落在不同的 swf 內才能達到最佳利用(沒辦法...還是要打包...XD )。不過 DI 這個東西是真的可以關注(真的很有趣),也希望 Spring 接下來的版本是更好用的...目前這個版本是有夠囉嗦的啦...
    BTW 那個 config xml 真的是有麻煩到... = =

    ReplyDelete

Post a Comment

Popular posts from this blog

[Swift3] weak 與 unowned 關鍵字

雖然在 Swift 中看起來"很像"是不需要煩惱內存管理的問題,不過實際上它還是遵循著自動引用計數 (ARC) 的規則,當一個物件沒有被其他對象引用時會自動被銷毀,如果三魂七魄沒有完全回位的話,就會有個靈體留在現世的空間裡,最經典的範例如下: 閉包(Closure)引用 classClassA { typealias Complete = ()->() var name : String var onComplete : Complete? init(_ name: String){ self.name = name print("Hello I am \(self.name)") onComplete = { print("\(self.name): onComplete!") // --> 閉包引用 self, 計數 + 1 } } deinit { print("deinit: \(self.name)") } } var a : ClassA? = ClassA("A") // --> 引用計數 + 1 a = nil // 2-1 = 1 還剩下 1 所以沒辦法銷毀 ---output------- Hello I am A 由於這邊的 onComplete 宣告為 Optional, 正確的做法要連同 onComplete 一起刪除才可以被回收,若不是 Optional 則會進入無法回收狀態: var b : ClassA? = ClassA("B") b?.onComplete = nil // --> 還好是 Optional 可以設成 nil 計數 - 1 b = nil // 計數 = 0 所以被回收 ---output------- Hello I am B deinit: B 但是做人不需要煩惱太多,這時候就出動 unowned 關鍵字讓物件可以順利被回收: onComplete = { [unowned self] in print...

[作品]Flex 3.4 + PureMVC 的企業級 RIA 應用

認識 Erin 的人都知道, Erin 最懶得寫作品集相關的文章,但是這個案子比較有趣,所以特別提出來聊一下囉! 廚櫃業某公司內部軟體,目前系統尚在 Beta 階段,所以下面圖片皆有模糊化處理。 [可擴充功能面板首頁,後台皆包含在管理系統內(有 iPhone 的 fu)] 這個案子是幫一家傳統公司做的專用軟體線上化,想要開發企業級 RIA 想當然爾就是使用 Flex 來處理囉! 整個案子前端是以 Flex SDK 3.4 + Flex Builder3, PureMVC MultiCore for AS3 , Utility - AS3 StateMachine 以及先前 Erin 所發表的 WidgetsConsole 來處理整個系統的轉換。 整個系統包含前後台共七大系統,分別是:估價,客戶,店面管理,貨品上架,會員管理,分店系統以及權限系統。超級管理員可以利用權限系統分別開出不同職級的權限,然後使用者透過同一入口,依照權限區分,畫面會顯示不同的功能。整個系統最複雜的部份當然是估價系統,由於櫥櫃的建立是透過選擇資料即時演算出來,更何況櫥櫃類的 BOM 表階層是怪物般的可怕...所以在 DB 的建置與前端資料整合的部分著實費了我們一番苦心。 [櫥櫃 BOM 表編輯視窗及櫥櫃 BOM 單物件材質指定] 此外,在 UI 設計上也特別花了一些心思。本案子 Target User 是管理者、店長與公司旗下的業務群,此公司成員年齡約 30-60 歲,皆為一般電腦使用者,所以 UI 設計及操作 Flow 必須比一般線上 RIA 更加友善,才能幫助縮減公司的人事教育花費。如放大整個系統的標準字 size;新增資料時不能碰的快速鍵會鎖定;產品類縮圖雙點擊即可觀看放大圖;操作 flow 皆以左上至右下結束以及利用畫面引導使用者操作都是一些設計上的巧思。 [新增估價單] [簡單易用的業務員用客戶系統] 此外這個專案在實作 PureMVC 過程當然是相當的快樂,因為它的彈性與權職切分實在太令人滿意了!不管是擴充性,Rich Data 管理又或者除錯都非常的容易。當然本人早就已經是 PureMVC 的忠實粉絲了...=P 快來加入 Flex + PureMVC 的行列吧~~ 結果這篇到最後變成 PureMVC 的勸進文...XD