Centralizing event handling in Actionscript 3: a good method to handle events for multiple objects with a single listener

One of the first cool things I learned about Actionscript 3, is how to handle events. Actionscript 3 is heavily tied with events, so the use and a deep understanding of events and listener should be one of the most important subject to face for an Actionscript developer. Although I’m far away to be considered an experienced Actionscript developer, I’ve just realized the power and the benefits of a centralized event handling architecture and I want to share my new knowledge by writing this post.  So… what means to “centralize events handling”?

Let’s start with a basic example of event handling, in which we attach a listener to an object, which simply will listen for a MouseEvent.MOUSE_OVER event:

myObject.addEventListener(MouseEvent.MOUSE_OVER, myObject.mouseOverHandler);

Now, let’s suppose that we need to handle even a MouseEvent.MOUSE_OUT event, we can simply add a new listener in this way:

myObject.addEventListener(MouseEvent.MOUSE_OUT, myObject.mouseOutHandler);

So the resulting code should be something like:

package {

    import flash.display.Sprite;

    public class MyObject extends Sprite {

        public function MyObject() {

            this.addEventListener(MouseEvent.MOUSE_OVER, this.mouseOverHandler);
            this.addEventListener(MouseEvent.MOUSE_OUT, this.mouseOutHandler);

        }

        private function mouseOverHandler(e:MouseEvent):void {

            // do something in response to MouseEvent.MOUSE_OVER event

        }

        private function mouseOutHandler(e:MouseEvent):void {

            // do something in response to MouseEvent.MOUSE_OUT event

        }

    }

}

Pretty straight and pretty clear, but let’s suppose that we have to deal with several “MyObject”, this approach will means to create an huge number of listeners which will increase memory usage and decrease application’s performance. One clever way to solve the problem and optimize code and performance is to delegate the event handling to a single listener, which handlers will use the Event’s target property in order to apply the code to the desired object.
A concrete example could be a scenario in which we have an application’s menu (represented by an AppMenu class) which contains several buttons (represented by an AppMenuItem class). The only listener will be related to AppMenu and will handle the MOUSE_OVER/MOUSE_OUT for each AppMenuItem:

package {

    import flash.display.Sprite;

    public class AppMenu extends Sprite {

        public function AppMenu() {

            this.addEventListener(MouseEvent.MOUSE_OVER, this.mouseOverHandler);

        }

        private function mouseOverHandler(e:MouseEvent):void {

            var ancestor:DisplayObject = DisplayObject(e.target).parent;

            if (e.target is AppMenuItem|| ancestor is AppMenuItem) {
                // activates the AppMenuItem
                AppMenuItem(ancestor is AppMenuItem ? ancestor : e.target).setActiveState();
                // subscribes for mouseOut event
                this.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
            }

        }

        private function mouseOutHandler(e:MouseEvent):void {

            var ancestor:DisplayObject = DisplayObject(e.target).parent;

            if (e.target is AppMenuItem || ancestor is AppMenuItem) {
                // deactivates the AppMenuItem
                AppMenuItem(ancestor is AppMenuItem ? ancestor : e.target).setDefaultState();
                // unsubscribes mouseOut listener
                this.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
            }

        }

    }

}

In the example above we simply attach only one listener for the MouseEvent.MOUSE_OVER, attaching a listener for MouseEvent.MOUSE_OUT is initially unnecessary because the event will occurs only after the previous event (and potentially it can never be used) , so the “cheapest” approach that we can have is to add the second listener only when necessary, that is when MOUSE_OVER occurs and remove it as soon as is used, that is inside mouseOverHandler() code. Both handlers (mouseOverHandler and mouseOutHandler) will invoke setActiveState() or setDefaultState() methods, after verify that the target of the event is an AppMenuItem or a child of it.
In this scenario, if we have 1 or 1000 AppMenuItem objects, we can handle 2 events for each object with only one listener, with the first approach we will have 2*N listeners, which means that to handle 1000 AppMenuItem we will have 2000 listeners!
As we can see, centralizing events handling is a really, really good thing!