So there's more or less 3 different schools of thought for implementing EventDispatcher in your classes. I've attempted to summarize the three most common approaches that I've seen, as well as the pros and cons of each approach. This is by no means a definitive list, but rather just a list from my perspective as an application developer. Feel free to add to it or contradict me in the comments.
-
Using a static initializer in the class:
This approach looks like this...
private static var EventDispatcher_mixin = EventDispatcher.initialize(MyClass.prototype);
In this approach, the class is responsible for declaring function variables for addEventListener, removeEventListener, and dispatchEvent. Then, the actual method implementations are mixed in from EventDispatcher to the class' prototype allowing the instances to use the EventDispatcher functionality themselves without further reliance on EventDispatcher.
Pros:
- The methods are mixed into the class prototype, thus saving memory and improving instantiation performance. The methods are only copied from EventDispatcher one time, so every time your class is instantiated the instance will automatically have the methods available to it through the prototype.
- Out of all the approaches I touch on, this one has the least overhead.
Cons:
- See the word prototype in there? It hasn't been deprecated, but who knows how long ActionScript classes will be compiled down to prototypes. Maybe this is really a non-issue, but I wouldn't want to have to re-write all of my classes in the future to work with Flash Player X if the runtime implementation changes.
- Really, the class should implement an "EventBroadcaster" interface so that the intention of the class is made known at compile-time. Yes, the class will have a "public var addEventListener:Function;" in it, but interfaces in ActionScript can only define methods, so you can't implement an interface. Thus the intent to dispatch events is not made explicit at compile-time, which could be construed as a design shortcoming.
- Something about that code just looks "ugly" and screams "hack" to me. Of course, that's totally my opinion...
Further reading:
-
Using the constructor to initialize the instance as an event source:
This approach looks like this...
// in the constructor EventDispatcher.initialize(this);
This approach is much the same as above. However, instead of initializing the prototype of the class, each instance of the class has to be initialized as an event source. In a singleton situation, this should provide roughly the same performance as copying the methods to the prototype. If you're going to be creating a lot of instances though, the performance of the constructor will be slightly slower (not by much though).
Pros:
- See the word prototype in there? Nope, not at all. Doing things this way is almost the same as above, except we're not relying on the underlying run time implementation for functionality.
- I think this approach is a little cleaner than the approach above, as far as readability is concerned.
Cons:
- Like the above approach, some sort of event broadcasting interface should be implemented. The class in this situation again needs to define function variables that get their implementations mixed in, but again, interfaces cannot define variables in AS 2.
- As stated, there are slight performance penalties for each instantiation.
- Some will argue that this code is redundant, since we're doing the same thing for every instance when it makes more sense to do it once at the class level.
Further reading:
-
Using composition:
This approach looks like this...
// in class body private var eventSrc:Object // in constructor EventDispatcher.initialize(eventSrc); // methods: public function registerView(view) { eventSrc.addEventListener("change", view); // more... } public function removeView(view) { eventSrc.removeEventListener("change", view); // more... } private function doSomething() { var eventObj:Object = new Object(); eventObj.target=this; eventObj.type = "change"; eventSrc.dispatchEvent(eventObj); }This approach is radically different. Instead of making the instance the event source, we're using composition to create an object that will be the source of the events for a particular instance. Then, instead of defining function variables that are mixed in, we're instead providing methods to register views (think MVC) that will automatically register the view for all of the applicable events via addEventListener on the eventSrc.
Pros:
- By using this approach, the intent can be made clear since we can finally implement an event broadcasting interface because there are no functions declared as variables. In this situation, we would implement an interface that defines the registerView and removeView methods.
- Again, there are no prototype tricks here. This is straight-up legit, "still-works-even-if-prototype-dies" code.
- I think this approach provides the most flexibility. If we want to change to AsBroadcaster instead of EventDispatcher we can just modify the event source and the few lines in registerView and removeView. The interface for our class stays consistent then with minimal effort. If we were using one of the previous 2 approaches we would have to make addEventListener a method that would invoke addListener, or we would have to update the interface and therefore force users of our class to change their code as well.
Cons:
- This method provides a bit of overhead for the extra function call to register the view.
- Like the above approach, we're initializing the eventSrc in the constructor, so every instance being created will have a slight performance hit.
- Obviously, registerView is somewhat specific to the MVC design pattern, but that may not be a con... I tend to use the MVC design pattern a lot in my Flash applications. You could, of course, just change the method name.
Further reading:
So, there you go.. that's my take on using EventDispatcher. I tend to use the third approach, composition, for the reasons listed above. Of course, you're free to use whatever method you like best. If you have anything to add, go ahead and leverage the comments.
