mattstuehler
mattstuehler

Reputation: 9292

Better practice for Flash AS3 RIA development - using events/listeners, or allowing children to call functions in parents?

I'm working on a web app built in Flash AS3.

At a high level - the app has a main screen, and several "modal dialog"-type screens that pop-up to manage various user interactions.

(This is a similar pattern I use in most of the apps I develop...)

Typically - when the user clicks a UI control on the dialog screen (e.g., button, text box, slider bar, etc.) - the main screen needs to react, or manage the consequences.

It seems like there are two general ways to handle this:

  1. Have the dialog screen dispatch events that the main screen listens for
  2. Allow the dialog screen to call functions in the main screen when those controls are clicked (which requires that the dialog screen maintain a reference to the main screen, and that the functions in the main screen are public)

In general - I understand that one of the key benefits of the first method is that the dialog screen isn't so tightly coupled; it's only responsibility is to broadcast the event. This would allow me to more easily use the dialog class in other contexts, or applications.

But for many RIAs I develop - a particular screen is SO SPECIFIC to the the application that there's no chance I'd ever reuse it in another application. So, the "easy re-use" benefit is minimal.

So - if you eliminate that benefit - which method is actually better? (More performant, less resource-intensive?)

For example - if I use events, then Flash needs to manage many listeners for events that may never occur. So - it might be more efficient if the dialog window could call a function in the main screen directly, instead of dispatching an event.

Which method is a better practice? What other benefits/pros/cons are there for each method?

Many thanks in advance.

Upvotes: 3

Views: 543

Answers (3)

meddlingwithfire
meddlingwithfire

Reputation: 1437

Avoid having your Dialog know about the Main screen class. Tightly-coupling makes debugging more difficult, and isn't truly representative of your intention -- your class should only have access to what it needs to accomplish its task. Anything additional is at best extra debugging overhead, and at worst, confusing for anyone else who has to read the code.

If you are worried about the performance implications of the AS3 event dispatching system (which you shouldn't be, unless you are dispatching hundreds of events per second), then use a delegate pattern instead. Since they use hard references, they will be very fast (easily comparable to just passing in your Main screen directly) and still provide the loose-coupling mojo. Your Dialog will have no idea what class it is sending messages to. The drawback when compared to the observer/listener pattern is that you only get a single "listener". Here's the pattern example:

IDialogDelegate.as

package
{
    public interface IDialogDelegate
    {
        function submitSelected():void;
    }
}

MainScreen.as

package 
{
    public class MainScreen extends Sprite implements IDialogDelegate
    {
         private var _dialog:Dialog;

         public function MainScreen()
         { 
             super();
             _dialog = new Dialog();
             _dialog.delegate = this;
             addChild(_dialog);
         }

         public function submitSelected():void
         {
             trace("handled!");
         }
    }
}

Dialog.as

package 
{
    public class Dialog extends Sprite
    {
        private var _delegate:IDialogDelegate
        private var _submitButton:Button;

        public function Dialog()
        {
            _submitButton = new Button();
            _anExampleActionButton.label = "Submit";
            _anExampleActionButton.addEventListener(MouseEvent.CLICK, onExampleActionSelected, false, 0, true);
            addChild(_anExampleActionButton);
        }

        public function set delegate(value:IDialogDelegate):void
        { _delegate = value; }

        private function onExampleActionSelected(event:MouseEvent):void
        {
            if(delegate != null)
            { delegate.submitSelected(); }
        }
}

Upvotes: 2

tousdan
tousdan

Reputation: 196

If you feel adventurous and like runtime errors, you could also pass around functions to be used as callbacks. You pass the function from the parent to the children and the children calls the function when needed.

Upvotes: 1

Jason Sturges
Jason Sturges

Reputation: 15955

MVC patterns and many developers would argue a decoupling of logic through events is a superior pattern.

This enables code-reuse, and is generally more stable in terms of life cycle then children calling functions from their parent. Parents add children, but children calling parents implies both objects must be aware and handle type definitions. There is no way to isolate a functional unit.

Perhaps your implementations are too specific, and abstracting more functionality would enable more re-use than you cite. Larger projects can quickly reach a complexity where it becomes difficult to manage pure procedural patterns.

Programmatic implementation should be passed downwards with the parent maintaining control of children. Events bubble upwards to ascendants.

Children maintaining control is similar to IoC (Inversion of Control) patterns, similar to Java Spring or what the Swiz Framework provides for Flash.

Functions will execute faster; however, the overhead you speak of is minimal unless you're speaking of thousands of classes performing a pattern. In that case, a singleton engine could assist speeding up the implementation.

Events that have no listeners essentially have no overhead.

Upvotes: 5

Related Questions