Copyright © 2003 O'Reilly Media, Inc. All Rights Reserved.
Flash Remoting: The Definitive Guide
By Tom Muck
September 2003
ISBN: 0-596-00401-X
http://www.oreilly.com/catalog/flashremoting/
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

Object-oriented programming (OOP) is at the opposite end of the programming spectrum from procedural programming. In true OOP, everything is an object. Code in the program does not exist if it is not part of an object. For that reason, Flash MX is not a true OOP environment; you don't have to create objects in order for the program to operate, although inline code is technically part of the current object where the code resides. Also, some of the key principles of OOP, such as data hiding (private, protected, and public members), are not implemented in ActionScript. Even though strict OOP is not entirely possible with Flash MX, you can get pretty darn close by simply using OOP principles in your coding style.

TIP: Flash 2004 and Flash Pro support ActionScript 2.0, which is much closer to a true OOP language than ActionScript 1.0. The following discussion applies whether you're using ActionScript 2.0 or trying to stretch ActionScript 1.0 to act as if it were truly object-oriented, although ActionScript 2.0 enforces stricter coding requirements.

Everything is an object

With OOP, you will want to create objects for everything. The application itself is an object; the user of the application is an object; every button on the screen is an object; the connection to the remote server is an object; the user's email address can be an object. An object is an instance of a class. A class is the coded blueprint for an object. Imagine the classes as rubber stamps, and the objects as the imprints you make when you use each rubber stamp. How you organize your classes and tie them together is one of the keys to understanding how OOP works.

OOP works in the exact opposite way that procedural programming works. In procedural programming, you ask yourself "What has to be done?" and then you do it. In OOP, you create abstract representations of each item in your application and ask yourself "How do they communicate?" Each class is created as a black box; you know what it does, you know what it needs, and you know what it returns. You don't have to know how it works, and you can remove it and substitute another black box with the same properties, methods, and events and the program will still work. Your class encapsulates the functionality and allows other classes to interact with it.

OOP in Flash Remoting

In Flash Remoting, there are several different ways you can encapsulate the functionality in objects:

Enclose your remote server calls in an object
Use broadcasters

A broadcaster is another object that you can use to simplify how remote method calls are handled on the client. When you use a broadcaster, you also have a listener. When the broadcaster broadcasts an event, the listener is automatically informed and performs some function. This is ideal for Flash Remoting, where a remote method does not provide an immediate response, but rather sends an onResult event back to the movie.

Use a Model/View/Controller (or Model/View/Presenter) architecture

The Model/View/Controller (MVC) design pattern allows you to separate functionality into distinct units. These patterns have been utilized by many Flash Remoting applications. The Model is the business object, handling the logic of the application; the View is the unit that handles the UI, such as the text fields, buttons, and UI components; and the Controller is the catalyst between the Model and the View, handling communication between them. In a Flash Remoting application, the Model is usually split between ActionScript on the client and the server-side services.

How to create your objects

There are several ways to implement OOP in Flash. Generally, the more abstract you make your classes, the easier the classes will be to understand for other programmers. I mean abstract in the sense of "evoking something's distilled essence," not "esoteric and obtuse." You should create classes that represent something meaningful. For example, your class should not be called RemoteService with methods that merely mirror your remote methods. This is obtuse and redundant, not abstract; it merely serves as a convenient way of accessing your services. An abstract class would be called Product, User, EmailAddress, or Search. These are human-readable objects that represent something meaningful to the application.

Objects are typically modeled before a line of code is written. Modeling involves identifying the objects in your application and documenting how they communicate via the properties, methods, and events of each object. Modeling can be done in many ways: using a Universal Modeling Language (UML) diagram, 3 × 5 cards (one for each object), or plotted on paper. In an OOP application, the more modeling you do in advance of coding, the easier it will be to create the objects and complete the coding successfully. In Flash Remoting, you must identify how an object will receive the remote result and how it will handle the result using an OOP mentality.

Responder objects in OOP

Throughout the book, I've shown a technique that makes sense in many situations—utilizing a custom responder object, like this:

function LoginResponder( ) {
 this.onResult = function (result) {
 if (result == true) {
 message_mc.message_txt.text = "User logged";
 } else {
 message_mc.message_txt.text = "User not logged";
 }
 };
 this.onStatus = function (error) {
 trace(error.description);
 };
}
myService.loginUser(new LoginResponder( ), user_txt.text, pwd_txt.text);

or this:

function LoginResponder ( ) {
}
LoginResponder.prototype.onResult = function (result) {
 if (result == true) {
 message_mc.message_txt.text = "User logged";
 } else {
 message_mc.message_txt.text = "User not logged";
 }
};
LoginResponder.prototype.onStatus = function (error) {
 trace(error.description);
};
myService.loginUser(new LoginResponder( ), user_txt.text, pwd_txt.text);

A better technique, however, is to use a callback function or a broadcaster within the responder object. The previous code is tied to the user interface, which is not an object-oriented approach; the user interface elements are not separate from the LoginResponder object. If you pass a callback function to the object, the LoginResponder is separate from the UI. You might start with a Responder class:

function Responder ( ) {}
Responder.prototype.onResult = function (results) {trace(results);};
Responder.prototype.onStatus = function (error) {trace(error.description);};

Then, create a LoginResponder class for specific functionality:

// LoginResponder extends Responder
#include "Responder.as"
function LoginResponder (myCallback) {
 this.prototype = new Responder( );
 this.callback = myCallback;
}

LoginResponder.prototype.onResult = function (result) {
 if (result == true) {
 this.callback("User logged", result);
 } else {
 this.callback("User not logged", result);
 }
};
doMessage = function (message) {
 message_mc.message_txt.text = message
};

The preceding LoginResponder class defines a responder object that uses the callback function passed to it. You can use it from another class designed to gather information from the UI:

myUserObject = new UserObject( );
myUserObject.loginUser("doMessage", user_txt.text, pwd_txt.text);

Inside the UserObject class you would have a loginUser( ) method, which would call the remote service:

#include "LoginResponder.as"
UserObject.prototype.loginUser = function (callback, username, password) {
 this.service.loginUser(new LoginResponder(callback), username, password);
};