Asea——輕量級的AS3模塊配置與加載管理庫


代碼已經托管到github:https://github.com/boycy815/asea

該庫的設計最初是為了方便配置RSL,后來發現功能逐漸與Spring接近,所以干脆對功能重新規划了一次取名為Asea,在AS3上實現了基本的IOC功能。

以下內容讓您學會如何使用Asea。

 

一. Hello World

 1 package
 2 {
 3     import com.alibado.asea.*;
 4     
 5     import flash.display.Sprite;
 6     
 7     public class AseaTest extends Sprite
 8     {
 9         public function AseaTest()
10         {
11             //定義配置xml
12             var xml:XML = new XML(<asea><trace value="string/hello world"/></asea>);
13             
14             //獲取根節點處理器
15             var asea:EaDrop = EaConfig.getDrop("asea");
16 
17             //定義上下文對象
18             var context:Object = {};
19 
20             //執行
21             asea.process(xml, [context]);
22         }
23     }
24     
25 }

除非您打算擴展它,否則使用Asea的僅需要四步。

配置xml中定義了您要執行的命令,命令的具體語法將在下面介紹。

上下文對象是xml命令執行的數據環境,換句話說,您可以在xml命令中從上下文對象中獲取數據和寫入數據,您可以嘗試把上下文對象另外保存起來,這樣您就可以通過它獲取到處理后的結果了。這里提醒一點,如果您的上下文對象並非動態對象,那么當您嘗試在xml上寫入上下文環境中不存在的屬性時,系統將報錯(ReferenceError),當然一般來說您沒有必要這么做。

根節點處理器就是一個大烤箱,您把執行命令和上下文數據交給它,它幫您處理。根節點處理器從EaConfig中獲取,一般來說獲取名字是“asea”的根節點處理器是不會錯的,除非您非常確切得知道您的根節點是什么標簽。另外方法process的第三個參數是成功后的回調,其定義應該是function(result:* = null):void,result處理后的結果,如果您的根節點是“asea”,那么result肯定是null,該回調存在的意義在於,考慮您的xml可能是異步處理的,比如在xml中加載個數據什么的。。process的第四個參數是出錯后的回調,定義是function(errorCode:int, message:String, target:String, xml:XML):void。

對了,您可能還注意到process的第二個參數並非直接是context對象,而是一個只有context一個元素的數組。這個問題涉及到作用域鏈,作用域鏈的作用將在后面講到。我知道這樣看起來不太友好,希望哪個好人能幫它再封裝一層吧。

 

二. 標簽處理器

Asea目前提供的標簽有:asea,class,get,if,lib,method,new,selector,trace,with,bean。

您可以在EaConfig這個類的drops屬性中找到這些定義,drops是個包含所有標簽處理器的數組,如果您定義了自己的標簽處理器,可以push到這個數組中即可生效。

所有的標簽處理器都繼承EaDrop這個類,您只需覆蓋onProcess方法和get name方法即可定義自己的標簽處理器。另外提醒一點,標簽處理器是無狀態的,全局唯一實例,所以如果您的變量不是定義在方法體內,就要小心處理了。

這里貼出了最簡單的標簽處理器

 

 1 package com.alibado.asea.drops
 2 {
 3     import com.alibado.asea.EaDrop;
 4     
 5     public class EaGet extends EaDrop
 6     {
 7         
 8         override public function get name():String
 9         {
10             return "get";
11         }
12         
13         
14         /**
15          * example:
16          * <get id="myPen" value="pen" >
17          */
18         override protected function onProcess(dom:XML, value:*, contexts:Array, onComplete:Function, onError:Function = null):void
19         {
20             onComplete(value);
21         }
22     }
23     
24 }

 

在EaGet中覆蓋了public function get name():String,需要在該方法中返回該標簽處理器的要處理的標簽名。

另外還要覆蓋protected function onProcess(dom:XML, value:*, contexts:Array, onComplete:Function, onError:Function = null):void,該方法的第一個參數是處理的xml,系統會保證該xml的根節點名就是get name中指定的名字;第二個參數value是在標簽中的value屬性在上下文環境中查詢到的數據,如果您不想知道查詢的結果想自己處理value屬性,那么您就去訪問xml.@value吧;contexts是上下文環境;onComplete是處理成功后的回調,如果您的標簽處理器會產生結果,那么就往onComplete里面傳遞結果吧,如果您的處理不產生結果,那也要調用一次onComplete,因為整個處理鏈是依賴onComplete進行的,如果您的標簽有id屬性且您傳遞了結果,那么系統會自動把您的結果保存在id屬性指定的地方,onError是處理出錯后的回調,定義已經在上文中提到過了。除非是特別嚴重的錯誤,否則我們不建議因為出錯而不調用onComplete。因為如果您不調用onComplete,系統會認為您的標簽尚未處理完成,整個處理過程將無法繼續。

 

三. 上下文環境的操作

上下文環境是個數組,其中下標為0的對象為“當前上下文”,數組末尾的對象為“根上下文”,一般來說“根上下文”是我們人為提供的,就像Hello World程序里定義的那個上下文對象。其他上下文對象則是在運行xml時產生的,至於為什么產生,什么時候會產生,這些問題在下文中介紹具體介紹標簽時講解。

有了上下文環境,我們就需要在上下文環境總讀取和寫入數據,通過標簽的value屬性可從上下文環境中讀取數據。

讀取的量可分常量與變量,常量分為string,number,boolean三種類型,例如"string/hello world"是字符串常量,"number/110"是數字常量,"boolean/true"是布爾型常量,其余寫法都算作變量。

@root是一個關鍵字,代表根上下文,我們可以以@root.attr的方式訪問根上下文的屬性,也可以@root.attr.attr2的方式進一步訪問。@this也是一個關鍵字,代表當前上下文環境。如果不使用關鍵字,比如myBall.x這樣的方式,則系統首先搜索當前上下文環境是否有myBall屬性,若是沒有,則再向上一級搜索,直到搜索到根上下文環境,這一點類似與JS的屬性訪問規則。

通過id屬性可保存標簽執行的結果,若是id為myBall.x,那么首先系統將在上下文環境中由內向外搜索myBall屬性,找到myBall對象后往其內設置x屬性。若是myBall屬性不存在,則將會在其當前上下文對象中建立myBall屬性,並且設置x屬性。同樣的myBall.positon.x的話,若是myBall不存在,則建立之,而后建立positon,最后設置x。id的設置同樣支持@root和@this,若是id直接等於@this或者@root,那么你就能直接把上下文對象給覆蓋了。。這相當危險但是有用。

 

四. 標簽詳解

asea:所有標簽中最重要的一個,該標簽什么屬性也不支持,但是它卻是其他標簽正常運行的容器,它一般作為根節點或者被其他標簽處理器作為父類;

bean:

        /**
         * example:
         * <bean id="myBean">
         *     <new id="newObj" value="Pic">
         *         <get value="box" />
         *         <get value="number/400" />
         *         <get value="number/300" />
         *         <get value="string/this is my title" />
         *     </new>
         *     <get id="newObj.a" value="box" />
         *     <get id="newObj.b" value="number/400" />
         *     <get id="newObj.c" value="number/300" />
         *     <get id="newObj.d" value="string/this is my title" />
         * </bean>
         */

定義一個對象的定義(並不直接執行內部代碼),內部第一個標簽必須是new標簽,new標簽執行前當前上下文對象是個空對象,new標簽之后當前上下文對象變成new出來的對象。而后的代碼可對new出來的對象設置屬性等操作。。。bean標簽的執行結果是一個對象定義,當每次被訪問時,都會執行一次對應的bean標簽內部的代碼並得到構造出來的內容。

class:

        /**
         * example: <class id="MyClass" value="com.alibado.lib.DemoClass" />
         */

定義一個類的別名,value屬性是類的完整命名,id是類的別名。實際上該別名就是上下文環境中的一個Class對象。

get:

        /**
         * example:
         * <get id="myPen" value="pen" >
         */

獲取屬性或者轉存屬性,get標簽的執行結果就是value屬性中指定的屬性。

if:

        /**
         * example:
         * <if value="id">
         *     <lib value="http://www.alibado.com/lib/myLib.swf" />
         *     <class id="MyClass" value="com.alibado.lib.DemoClass" />
         * </if>
         * 
         */

邏輯判斷功能的標簽,若是value內的值是布爾型true,則執行內部內容,否則不執行任何操作。

lib:

        /**
         * example: <lib value="http://www.alibado.com/lib/myLib.swf" />
         */

該標簽是動態加載swf庫到當前applicationDomain。

method:

        /**
         * example:
         * <method id="pic" value="draw">
         *     <get value="number/400" />
         *     <get value="number/300" />
         *     <get value="string/this is my title" />
         * </method>
         */

該標簽是執行一個方法,其value值對應的對象必須是個Function,否則結果你懂的。。標簽的輸出是函數執行結果。標簽的子標簽是參數。實際上參數可以是任何標簽,只要能產生輸出均可,內部標簽的當前上下文對象是個數組,該數組將最終成為Function執行的參數。

new:

        /**
         * example:
         * <new id="myPic" value="Pic">
         *     <get value="box" />
         *     <get value="number/400" />
         *     <get value="number/300" />
         *     <get value="string/this is my title" />
         * </new>
         */

該標簽的功能是實例化一個對象,value的值可以是上下文中的Class對象,也可以是類的全名(先搜索上下文內容)。new標簽輸出結果是實例化的結果。new標簽內部的標簽是構造函數參數,其實現原理與method標簽一樣,另外,構造函數參數個數不能超過十個。。。

selector:

        /**
         * example:
         * <selector>
         *     <if value="id1">
         *         <lib value="http://www.alibado.com/lib/myLib.swf" />
         *         <class id="MyClass" value="com.alibado.lib.DemoClass" />
         *     </if>
         *     <if value="id2">
         *         <lib value="http://www.alibado.com/lib/myLib.swf" />
         *         <class id="MyClass" value="com.alibado.lib.DemoClass" />
         *     </if>
         * </selector>
         * 
         * 子節點規則:onComplete參數第一個為true則跳出,否則繼續。
         */

該標簽類似於switch,當其內部標簽的執行結果是true的時候,才停止執行,否則將一直執行下去。

trace:

        /**
         * example: <trace value="string/hello world" />
         */

該標簽直接在控制台輸出value的內容,用於調試。

with:

        /**
         * example:
         * <with value="ball">
         *     <get id="aa" value="number/400" />
         *     <get id="bb" value="number/300" />
         *     <get id="cc" value="string/this is my title" />
         * </with>
         */

該標簽為其內部的標簽創造一個當前上下文對象,內部標簽的當前上下文對象變成由value指定的對象。

include:

        /**
         * example:
         * <include value="pen.xml" >
         */

該標簽可導入一個外部的xml或者上下文中存在的一個xml對象,系統首先搜索value中給定的值是否在上下文中有對應的xml對象,若是有則處理之,若是沒有則搜索是否存在對應的String對象,若是有則將其視為外部xml的URL並加載之,若是沒有則將value內容視為外部XML的URL並加載之。載入的XML與外部享有相同的上下文環境。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM