2010年2月15日 星期一

ActionScript 3.0 Proxy 測試



MyProxy
package tw.right929
{
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    use namespace flash_proxy
   
    public dynamic class MyProxy extends Proxy
    {
        private var _obj:Object            =    new Object();
        private var _properties:Array    =    new Array();
        private var _needUpdateProperties:Boolean    =    false;
       
        public function MyProxy()
        {
            super();
        }
       
        override flash_proxy function callProperty(name:*, ... rest):*
        {
            trace("callProperty "+name+" "+rest);
            return _obj[name].apply(this, rest);
        }
       
        override flash_proxy function deleteProperty(name:*):Boolean
        {
            trace("deleteProperty "+name);
            _needUpdateProperties    =    true;
            return delete _obj[name];
        }
       
        override flash_proxy function getDescendants(name:*):*
        {
            trace("getDescendants "+name);
            return _obj[name];
        }
       
        override flash_proxy function getProperty(name:*):*
        {
            trace("getProperty "+name)
            return _obj[name];
        }
       
        override flash_proxy function hasProperty(name:*):Boolean
        {
            trace("hasProperty "+name);
            updateProperties();
            return(name in _obj);
        }
       
        override flash_proxy function isAttribute(name:*):Boolean
        {
            trace("isAttribute "+name);
            return true;
        }
       
        override flash_proxy function nextName(index:int):String
        {
            trace("nextName "+index);
            updateProperties();
            return _properties[index-1].toString();
        }
       
        override flash_proxy function nextNameIndex(index:int):int
        {
            trace("nextNameIndex "+index);
            updateProperties()
            if (index < _properties.length)
                return index + 1;
            else
                return 0;
        }
       
        override flash_proxy function nextValue(index:int):*
        {
            trace("nextValue "+index);
            updateProperties();
            return _obj[_properties[index-1]];
        }
       
        override flash_proxy function setProperty(name:*, value:*):void
        {
            trace("setProperty "+name+" = "+value);
            _needUpdateProperties    =    true;
            _obj[name] = value;
        }
       
        private function updateProperties():void
        {
            if(_needUpdateProperties)
            {
                _properties    =    new Array();
                for (var p:String in _obj)
                    _properties.push(p);
                _needUpdateProperties    =    false;
            }
        }
    }
}

nextName ,nextNameIndex ,nextValue
這三個方法的實作要注意,
傳入的index,代表的意思和想像中的不同(請參考下面的執行結果),
index=0 時代表的是一開始,1是代表第一個屬性的index之後依此類推。

TestMyProxy.mxml


<?xml version="1.0" encoding="utf-8"?>
<s:Application creationComplete="init()" xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768">
    <fx:Script>
        <![CDATA[
            import tw.right929.MyProxy;
           
            private var myP:MyProxy;
           
            private function init():void
            {
                myP    =    new MyProxy();
                myP["name"]    =    "one";//setProperty name = one
                myP["showName"]    =    function ():void
                    {
                        trace("myName is "+this["name"]);
                    };//setProperty showName = function Function() {}
                trace(myP.name);//getProperty name ; one
                trace(myP.showName);//getProperty showName ; function Function() {}
                myP.showName();//callProperty showName ; myName is one
                delete myP["name"];//deleteProperty name
                trace(myP["name"]);//undefined
                myP.showName();//callProperty showName ; myName is one
                delete myP["showName"];//deleteProperty showName
                //myP.showName();//發生錯誤
               
                trace(myP.hasOwnProperty("p1"));//hasProperty p1 ; false
                myP["p1"]    =    "p1";
                trace(myP.hasOwnProperty("p1"));//hasProperty p1 ; true
                trace("p1" in myP);//hasProperty p1 ; true
                myP["p2"]    =    "p2";
                myP["f1"]    =    function ():void{};
                myP["f2"]    =    function ():void{};
                for(var p:* in myP)
                {
                    trace(p);
                }
                /*
                nextNameIndex 0
                nextName 1
                p2
                nextNameIndex 1
                nextName 2
                f2
                nextNameIndex 2
                nextName 3
                p1
                nextNameIndex 3
                nextName 4
                f1
                nextNameIndex 4
                */
               
                myP.p1    =    "pp1";
                trace(myP.p1);
                trace(myP.f1);
               
            }
        ]]>
    </fx:Script>
</s:Application>


可惜,若想使用Proxy的語法糖衣,就失去和Dictionary一樣的key值特性。
上例中,若把myP["p2"]改myP[{}] ,myP["f2"]改myP[{}],
則迴圈中的結果會變成p1 , f1 , [Object object],
這是因為在setProperty時,傳入的name已經被改成QName了,
真是太可惜了。


使用Proxy的特性和prototype的概念,
也許可以做出想要的,非常動態的類別結構。

沒有留言:

張貼留言

追蹤者