How to share an Array between all Classes in an application?

后端 未结 3 772
时光取名叫无心
时光取名叫无心 2021-01-21 22:10

I want to share an Array which all classes can \"get\" and \"change\" data inside that array. Something like a Global array or Multi Access array. How this is possible with Acti

3条回答
  •  不要未来只要你来
    2021-01-21 22:52

    As this question was linked recently I would add something also. I was proposed to use singleton ages ago and resigned on using it as soon as I realized how namespaces and references work and that having everything based on global variables is bad idea.

    Aternative

    Note this is just a showcase and I do not advice you to use such approach all over the place.

    As for alternative to singleton you could have:

    public class Global {
        public static const myArray:Alternative = new Alternative();
    }
    

    and use it almost like singleton:

    var ga:Alternative = Global.myArray;
    ga.e.addEventListener(GDataEvent.NEW_DATA, onNewData);
    ga.e.addEventListener(GDataEvent.DATA_CHANGE, onDataChange);
    ga.push(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "ten");
    trace(ga[5]); // 5
    

    And your Alternative.as would look similar to singleton one:

    package adnss.projects.tchqs 
    {
        
        import flash.utils.Proxy;
        import flash.utils.flash_proxy;
    
        public class Alternative extends Proxy
        {
            private var _data:Array = [];
            private var _events:AltEventDisp = new AltEventDisp();
            private var _dispatching:Boolean = false;
            public var blockCircularChange:Boolean = true;
            
            public function Alternative() {}
            
            override flash_proxy function getProperty(id:*):* {var i:int = id;
                return _data[i += (i < 0) ? _data.length : 0];
                //return _data[id]; //version without anal item access - var i:int could be removed. 
            }
            
            override flash_proxy function setProperty(id:*, value:*):void { var i:int = id;
                if (_dispatching) { throw new Error("You cannot set data while DATA_CHANGE event is dipatching"); return; }
                i += (i < 0) ? _data.length : 0;
                if (i > 9 ) { throw new Error ("You can override only first 10 items without using push."); return;}
                _data[i] = value;
                if (blockCircularChange) _dispatching = true;
                _events.dispatchEvent(new GDataEvent(GDataEvent.DATA_CHANGE, i));
                _dispatching = false;
            }
            
            public function push(...rest) {
                var c:uint = -_data.length + _data.push.apply(null, rest);
                _events.dispatchEvent(new GDataEvent(GDataEvent.NEW_DATA, _data.length - c, c));
            }
            
            public function get length():uint { return _data.length; }
            
            public function get e():AltEventDisp { return _events; }
            
            public function toString():String { return String(_data); }
        }
    
    }
    
    import flash.events.EventDispatcher;
    /**
     * Dispatched after data at existing index is replaced. 
     * @eventType   adnss.projects.tchqs.GDataEvent
     */
    [Event(name = "dataChange", type = "adnss.projects.tchqs.GDataEvent")]
    /**
     * Dispatched after new data is pushed intwo array.
     * @eventType   adnss.projects.tchqs.GDataEvent
     */
    [Event(name = "newData", type = "adnss.projects.tchqs.GDataEvent")]
    class AltEventDisp extends EventDispatcher { }
    

    The only difference form Singleton is that you can actually have multiple instances of this class so you can reuse it like this:

    public class Global {
        public static const myArray:Alternative = new Alternative();
        public static const myArray2:Alternative = new Alternative();
    }
    

    to have two separated global arrays or even us it as instance variable at the same time.

    Note

    Wrapping array like this an using methods like myArray.get(x) or myArray[x] is obviously slower than accessing raw array (see all additional steps we are taking at setProperty).

    public static const staticArray:Array = [1,2,3];
    

    On the other hand you don't have any control over this. And the content of the array can be changed form anywhere.

    Caution about events

    I would have to add that if you want to involve events in accessing data that way you should be careful. As with every sharp blade it's easy to get cut. For example consider what happens when you do this this:

    private function onDataChange(e:GDataEvent):void {
        trace("dataChanged at:", e.id, "to", Global.myArray[e.id]);
        Global.myArray[e.id]++;
        trace("new onDataChange is called before function exits"); 
    }
    

    The function is called after data in array was changed and inside that function you changing the data again. Basically it's similar to doing something like this:

    function f(x:Number) {
        f(++x);
    }
    

    You can see what happens in such case if you toggle myArray.blockCircularChange. Sometimes you would intentionally want to have such recursion but it is likely that you will do it "by accident". Unfortunately flash will suddenly stop such events dispatching without even telling you why and this could be confusing.

    Download full example here

    Why using global variables is bad in most scenarios?

    I guess there is many info about that all over the internet but to be complete I will add simple example.

    Consider you have in your app some view where you display some text, or graphics, or most likely game content. Say you have chess game. Mayby you have separated logic and graphics in two classes but you want both to operate on the same pawns. So you create your Global.pawns variable and use that in both Grahpics and Logic class.

    Everything is randy-dandy and works flawlessly. Now You come with the great idea - add option for user to play two matches at once or even more. All you have to do is to create another instance of your match... right?

    Well you are doomed at this point because, every single instance of your class will use the same Global.pawns array. You not only have this variable global but also you have limited yourself to use only single instance of each class that use this variable :/

    So before you use any global variables, just think twice if the thing you want to store in it is really global and universal across your entire app.

提交回复
热议问题