2010年2月16日 星期二

ActionScript 3.0 實驗,動態繼承



AdvancedObject
package tw.right929
{
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
    import flash.utils.getDefinitionByName;
    import flash.utils.getQualifiedClassName;
   
    use namespace flash_proxy
   
    public dynamic class AdvancedObject extends Proxy
    {
        /**
         * 統一改變這個屬於這個類別物件的missFunction
         */
        public static var missFunction:Function    =    function (name:*, rest:Array):* {return undefined};
        /**
         * 統一改變這個屬於這個類別物件的missProperty
         */
        public static var missProperty:Function    =    function (name:*):* {return undefined};
       
        private var _obj:Object            =    new Object();
        private var _properties:Array    =    new Array();
        private var _needUpdateProperties:Boolean    =    false;
       
        private var _superObj:Object;
       
        private var _missFunction:Function;
        private var _missProperty:Function;
       
        public function AdvancedObject()
        {
            super();
        }
       
        /**
         * 設定父物件。
         */
        public final function set superObj(v:Object):void
        {
            _superObj    =    v;
        }
        public final function get superObj():Object
        {
            return _superObj;
        }
       
        /**
         * 若呼叫了不存在的方法,則會呼叫這個方法,預設值是傳回undefined。
         */
        public final function set missFunction(v:Function):void
        {
            _missFunction    =    v;
        }
        public final function get missFunction():Function
        {
            if(_missFunction)
                return _missFunction;
            return getDefinitionByName(getQualifiedClassName(this))["missFunction"] as Function;
        }
       
        /**
         * 若想取得不存在的屬性,則會呼叫這個方法,預設值是傳回undefined。
         */
        public final function set missProperty(v:Function):void
        {
            _missProperty    =    v;
        }
        public final function get missProperty():Function
        {
            if(_missProperty)
                return _missProperty;
            return getDefinitionByName(getQualifiedClassName(this))["missProperty"] as Function;
        }
       
        /**
         * 先看自已有沒有這個方法,若沒有呼叫superObj的,若superObj也沒有,統一呼叫這個物件的missFunction。
         */
        override flash_proxy function callProperty(name:*, ... rest):*
        {
            if(_hasProperty(name))
                return _obj[name].apply(this , rest);
            else if(_superObj && _superObj.hasOwnProperty(name))
                return _superObj[name].apply(this , rest);
            else
                return missFunction(name , rest);
        }
       
        /**
         * 這個方法應該要只能刪掉自已的,不能刪掉繼承鏈上的屬性。
         */
        override flash_proxy function deleteProperty(name:*):Boolean
        {
            _needUpdateProperties    =    true;
            return delete _obj[name];
        }
       
        override flash_proxy function getDescendants(name:*):*
        {
            return _obj[name];
        }
       
        /**
         * 先看自已有沒有這個屬性,若沒有找superObj的,若superObj也沒有,統一呼叫這個物件的missProperty。
         */
        override flash_proxy function getProperty(name:*):*
        {
            if(_hasProperty(name))
                return _obj[name];
            else if(_superObj && _superObj.hasOwnProperty(name))
                return _superObj[name];
            else
                return missProperty(name);
        }
       
        /**
         * 尋找是否有這個屬性,包含superObj。
         */
        override flash_proxy function hasProperty(name:*):Boolean
        {
            updateProperties();
            if(_hasProperty(name))
                return true;
            else if(_superObj && _superObj.hasOwnProperty(name))
                return true;
            else
                return false;
        }
        /**
         * 尋找是否有這個屬性,不包含superObj。
         */
        private function _hasProperty(name:*):Boolean
        {
            if(name is QName)
                name    =    name.localName;
            return(name in _obj);
        }
       
        override flash_proxy function isAttribute(name:*):Boolean
        {
            return true;
        }
       
        override flash_proxy function nextName(index:int):String
        {
            updateProperties();
            return _properties[index-1].toString();
        }
       
        override flash_proxy function nextNameIndex(index:int):int
        {
            updateProperties()
            if (index < _properties.length)
                return index + 1;
            else
                return 0;
        }
       
        override flash_proxy function nextValue(index:int):*
        {
            updateProperties();
            return _obj[_properties[index-1]];
        }
       
        /**
         * 先看自已有沒有這個屬性,若沒有找superObj的,若superObj也沒有,幫自已新增這個屬性。
         */
        override flash_proxy function setProperty(name:*, value:*):void
        {
            _needUpdateProperties    =    true;
            if(_hasProperty(name))
                _obj[name] = value;
            else if(_superObj && _superObj.hasOwnProperty(name))
                _superObj[name] = value;
            else
                _obj[name] = value;
        }
       
        /**
         * 重整自已的屬性清單。
         */
        private function updateProperties():void
        {
            if(_needUpdateProperties)
            {
                _properties    =    new Array();
                for (var p:String in _obj)
                    _properties.push(p);
                _needUpdateProperties    =    false;
            }
        }
    }
}

這個類別的功能尚未完備,僅是為了測試而生。


TestDynamicInheritance.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 flash.display.*;
           
            import tw.right929.AdvancedObject;
            private function init():void
            {
                var classOne:AdvancedObject    =    new AdvancedObject();
                classOne.name    =    "classOne name";
                var classTwo:AdvancedObject    =    new AdvancedObject();
                classTwo.showName    =    function ():String
                                        {
                                            return "classTwo showName "+this.name;
                                        };
                var classThree:AdvancedObject    =    new AdvancedObject();
                classThree.showName    =    function ():String
                                        {
                                            return "classThree showName "+this.name;
                                        };
               
                trace(classOne.showName());//undefined
                trace(classTwo.showName());//classTwo showName undefined
                trace(classThree.showName());//classThree showName undefined
               
                classTwo.superObj    =    classOne;
                classThree.superObj    =    classTwo;
                trace(classTwo.showName());//classTwo showName classOne name
                trace(classThree.showName());//classThree showName classOne name
               
                classTwo.name    =    "two";
                trace(classOne.name);//two
                trace(classTwo.showName());//classTwo showName two
                trace(classThree.showName());//classThree showName two
                //因為two和three的父類別都是one,而改了two的name會去變動one的name,所以three的name也會跟著變動。
               
                classTwo.superObj    =    null;
                classThree.superObj    =    null;
                trace(classTwo.showName());//classTwo showName undefined
                trace(classThree.showName());//classThree showName undefined
                //脫離繼承關係後,連name的屬性也跟著消失。
               
                classThree.name    =    "three";
                classTwo.superObj    =    classOne;
                classThree.superObj    =    classTwo;
                trace(classTwo.showName());//classTwo showName two
                trace(classThree.showName());//classThree showName three
                //three因為在沒繼承的關係下,新增了name屬性,所以three的name屬性蓋掉了two的name屬性。
               
                classOne.superObj    =    classThree;
                trace(classOne.showName());//classThree showName two
                trace(classTwo.showName());//classTwo showName two
                trace(classThree.showName());//classThree showName three
                //循環繼承,one因為自已沒有showName方法,所以去呼叫他的父類別three的showName方法,然後套上自已所有的name。
                //這裡有個風險,若是指定一個沒有在繼承圈中的屬性或方法,就會無限迴圈了。
               
                classThree.superObj    =    null;
                classThree.missFunction    =    function (name:*, rest:Array):*
                                            {
                                                var temp:String    =    name.toString()
                                                if(temp.indexOf("create_") == 0)
                                                {
                                                    temp    =    temp.substr(7).replace(/_/g , ".")
                                                    var c:Class    =    flash.utils.getDefinitionByName(temp) as Class;
                                                    var r:Object    =    new c();
                                                    if(rest.length > 0)
                                                    {
                                                        var data:Object    =    rest[0]
                                                        for(var p:String in data)
                                                            r[p]    =    data[p];
                                                    }
                                                    return r;
                                                }
                                                return undefined;
                                            };
                var s:Sprite    =    classThree.create_flash_display_Sprite({x:10 , y:100 , rotationX:20 , rotationY:200}) as Sprite;
                trace(s.x+"    "+s.y+"    "+s.rotationX+"    "+s.rotationY);//10    100    20    200
                var classZero:AdvancedObject    =    classThree.create_tw_right929_AdvancedObject
                                                    (
                                                        {
                                                            superObj:classThree ,
                                                            name:"zero" ,
                                                             myClass:function ():String {return flash.utils.getQualifiedClassName(this)}
                                                        }
                                                    ) as AdvancedObject;
                trace(classZero.showName());//classThree showName zero
                trace(classZero.myClass());//tw.right929::AdvancedObject
                classTwo.superObj    =    classZero;
                trace(classTwo.showName());//classTwo showName zero
                trace(classTwo.myClass());//tw.right929::AdvancedObject
            }
        ]]>
    </fx:Script>
</s:Application>


初步測試正常,只有在循環繼承中若指定不存在的屬性和方法會產生無限迴圈。

接下來再來做一件更有趣的事
修改TestDynamicInheritance.mxml,在最後加上
private var _thisName:String    =    "thisName";
classTwo.showName    =    function ():String
                {
                    _thisName    =    "new thisName";
                    return "classTwo showName "+_thisName;
                };
                trace(classTwo.showName());//classTwo showName new thisName
                trace(_thisName);//new thisName
注意到,傳進去給classTwo.showName的function中,我們修改了private的變數,並指定為新值。
就上面的例子來說,
在function中的this._thisName是undefined,而_thisName則是"thisName",
在function中的this.name是"two",而name則是"TestDynamicInheritance0"。

沒有留言:

張貼留言

追蹤者