2010年3月2日 星期二

Trigger ,特定條件觸發器(3/7更新)

方便在達成特定的條件時,觸發特定的方法。
並在從達成變未達成時,也會觸發特定的方法。



Trigger
package tw.right929.proxy
{
    import flash.utils.*;
    
    use namespace flash_proxy
    
    /**
     * <p>
     * 達成條件時,發動函式whenInDo.call(thisObjectForIn),<br/>
     * 從達成條件變成未達成時,發動函式whenOutDo.call(thisObjectForOut)。
     * </p>
     */
    public dynamic class Trigger extends Proxy
    {
        private var _propertyMap:Object        =    new Object();
        
        private var _triggerCount:int    =    0;
        private var _map:Dictionary    =    new Dictionary();
        
        public function Trigger()
        {
            super();
        }
        
        /**
         * 新增一個條件觸發式。
         * 若加入時,Trigger已是滿足條件的狀態,會直接發動函式whenInDo.call(thisObjectForIn)。
         */
        public function $addTrigger(conditions:* , whenInDo:Function , whenOutDo:Function , thisObjectForIn:*=null , thisObjectForOut:*=null):*
        {
            _triggerCount++;
            _map[_triggerCount]    =    new $ConditionInfo(conditions , whenInDo , whenOutDo , thisObjectForIn , thisObjectForOut);
            _map[_triggerCount].testConditions(_propertyMap , _propertyMap);
            return _triggerCount;
        }
        
        /**
         * 移除一個條件觸發式。
         */
        public function $removeTrigger(triggerID:*):void
        {
            _map[triggerID].die();
            delete _map[triggerID];
        }
        
        /**
         * 一次修改許多絛件式。
         */
        public function $setConditions(conditions:*):void
        {
            for(var p:String in conditions)
                _propertyMap[p]    =    conditions[p];
            _update(conditions);
        }
        
        /**
         * 把物件清空,方便回收。
         */
        public function die():void
        {
            for(var triggerID:* in _map)
                $removeTrigger(triggerID);
            
            for(var p:* in _propertyMap)
                delete _propertyMap[p];
            
            _propertyMap    =    null;
            _map    =    null;
        }
        
        /**
         * conditions為改變的條件。
         * 檢查所有觸發式,若有符合,則發動。
         */
        private function _update(conditions:*):void
        {
            for each(var conditionInfo:$ConditionInfo in _map)
            {
                conditionInfo.testConditions(_propertyMap , conditions);
            }
        }
        
        override flash_proxy function setProperty(name:*, value:*):void
        {
            if(this[name] == value)
                return;
            _propertyMap[name]    =    value;
            var conditions:Object    =    new Object();
            conditions[name]    =    value;
            _update(conditions);
        }
        
        override flash_proxy function deleteProperty(name:*):Boolean
        {
            return delete _propertyMap[name]; 
            var conditions:Object    =    new Object();
            conditions[name]    =    false;
            _update(conditions);
        }
        
        override flash_proxy function getProperty(name:*):*
        {
            return _propertyMap[name];
        }
        
        override flash_proxy function hasProperty(name:*):Boolean
        {
            return name in _propertyMap;
        }
    }
}

class $ConditionInfo
{
    public var conditions:*;
    public var whenInDo:Function;
    public var whenOutDo:Function;
    public var thisObjectForIn:*;
    public var thisObjectForOut:*;
    
    private var _inConditions:Boolean    =    false;
    
    public function $ConditionInfo(conditions:* , whenInDo:Function , whenOutDo:Function , thisObjectForIn:*=null , thisObjectForOut:*=null)
    {
        this.conditions    =    conditions;
        this.whenInDo    =    whenInDo;
        this.whenOutDo    =    whenOutDo;
        this.thisObjectForIn    =    thisObjectForIn;
        this.thisObjectForOut    =    thisObjectForOut;
    }
    
    public function testConditions(conditionsMap:Object , change:*):void
    {
        if(checkChange(change))
        {
            if(_inConditions)
            {
                _inConditions    =    false;
                if(whenOutDo != null)
                    whenOutDo.call(thisObjectForOut);
            }
            else
            {
                for(var p:String in conditions)
                {
                    if(conditionsMap[p] == undefined)
                        return;
                    if(conditionsMap[p] != conditions[p])
                        return;
                }
                _inConditions    =    true;
                if(whenInDo != null)
                    whenInDo.call(thisObjectForIn);
            }
        }
    }
    
    public function die():void
    {
        conditions    =    null;
        whenInDo    =    null;
        whenOutDo    =    null;
        thisObjectForIn    =    null;
        thisObjectForOut    =    null;
    }
    
    private function checkChange(change:*):Boolean
    {
        for(var p:String in change)
        {
            if(p in conditions)
                return true;
        }
        return false;
    }
}

測試
<?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.proxy.Trigger;
            
            private function init():void
            {
                var trigger:Trigger    =    new Trigger();
                trigger.$addTrigger({A:true}             , onInA    , null        , this);
                trigger.$addTrigger({B:true}             , onInB    , onOutB    , this);
                trigger.$addTrigger({C:true , D:true}     , null    , onOutCD    , null , this);
                trigger.$addTrigger({E:10}                 , onInE    , null        , this);
                
                trigger.A    =    true;    //onInA
                trigger.B    =    true;    //onInB
                trigger.C    =    true;
                trigger.D    =    true;    
                
                trigger.A    =    false;    
                trigger.B    =    false;    //onOutB
                trigger.C    =    false;    //onOutCD
                trigger.D    =    false;    
                
                trigger.E    =    0;
                trigger.E    =    10;        //onInE
                
                trigger.die();
            }
            
            private function onInA():void
            {
                trace("onInA");
            }
            
            private function onInB():void
            {
                trace("onInB");
            }
            private function onOutB():void
            {
                trace("onOutB");
            }
            
            public function onOutCD():void
            {
                trace("onOutCD");
            }
            
            public function onInE():void
            {
                trace("onInE");
            }
        ]]>
    </fx:Script>
</s:Application>

沒有留言:

張貼留言

追蹤者