- Home
- Articles
- Best Practices
- Flash Remoting Best Practices

Problems with OOP
Copyright © 2003 O'Reilly Media, Inc. All Rights Reserved. | ![]() |
| This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org. | |
There are a few inconsistencies with Flash Remoting when working with objects. The asynchronous nature of Flash Remoting makes it difficult to create objects that separate UI and content from your remote results. Because the results are accessed within an onResult( ) method, you might be tempted to access interface elements from within the same method. This would break the principle of encapsulation, which basically says that objects should behave as black boxes. In a properly encapsulated object, the internal workings of the object don't rely on external items such as UI elements. You can overcome the obstacle by using a broadcaster inside the onResult( ) and onStatus( ) methods, or by passing a callback method to the object, which would be called inside of onResult( ) or onStatus( ), as we'll see shortly.
Another problem involves having a service object as part of a custom object that is sent to the server in a remote method. It is a natural tendency to want to encapsulate the object to be self-sufficient and exist as a unit. One way to do that is to have your remote service as a property of the object. Unfortunately, this causes the remote call to fail due to an internal fault with Flash Remoting. The Macromedia Pet Market blueprint application (http://www.macromedia.com/devnet/mx/blueprint) suffers from this problem, but the programmers worked around the issue by copying the object properties to another object before calling the remote service. Workarounds such as these are commonplace, as Flash Remoting is still in its infancy and has a few kinks to work out.
Callback example
This section demonstrates an example that uses callback functions and shows how the procedural code from Example 12-3 might be implemented as an OOP application. There are a few extra steps involved in turning a simple example into a full-fledged OOP application. You'll have to start with a new movie named HelloUserOOP.fla and follow these steps (the completed file is available at the online Code Depot):
-
Add 2 layers to the timeline: actions and ui.
-
Create a new MovieClip using Insert ? New Symbol.

Figure 12-1. Creating a new MovieClip for HelloUser
-
Inside the symbol, rename layer Layer1 to actions.
-
Define a HelloUserClass class in the first frame of the actions layer, as follows. This class initializes the gateway and is the basis of our application:
#initclip
#include "NetServices.as"
function HelloUserClass (url) {
this.init(url);
}
Object.registerClass("HelloUserSymbol", HelloUserClass);
HelloUserClass.prototype.init = function (url) {
this.testingUrl = url;
NetServices.setDefaultGatewayURL(this.testingUrl);
this._conn= NetServices.createGatewayConnection( );
};
#endinitclipNavigate back to the main movie and enter the following ActionScript into the actions layer of the main timeline. Notice the include file, User.as, which is a custom class that we'll set up for this application. The initialization code shown creates a NetConnection object upon loading (through the HelloUserClass), and creates a User object. From this code, you can see that the User object instance is calling three different methods: setService( ), setName( ), and sayHello( ). The
submit_pbbutton has a private method, displayMessage( ), within the anonymous function built for the onRelease event. A reference to displayMessage( ) is passed to the User object as a callback function:#include "com/oreilly/frdg/User.as"
// Call the service when the user clicks the Submit button.
if (initialized == undefined) {
initialized = true;
_global.app = new HelloUserClass("http://localhost/flashservices/gateway");
var servicePath = "com.oreilly.frdg.HelloUser";
app.myUser = new User("User");
app.myUser.setService(app._conn, servicePath);
}
submit_pb.onRelease = function ( ) {
displayMessage = function (message) {
results_txt.text = message;
}
app.myUser.setName(userName_txt.text);
app.myUser.sayHello(displayMessage, displayMessage);
}; -
Create the User class. The User.as file should be saved in your Flash configuration directory under Configuration\Include\com\oreilly\frdg. Our class files are using the same naming convention as the server-side services that have been used throughout the book. Alternatively, you can save the class files in the same directory as your .fla file—using the same subdirectories, com\oreilly\frdg. The User.as file contains the code shown here:
/*
User class
public User
constructor:
new User( ); // Default user with no arguments
new User(name); // Set a default <em>name</em> property
arguments:
name: string
properties:
service: the remote service with which the user interacts
name: the name of the user
methods:
getName: retrieve <em>name</em> property
setName: set <em>name</em> property
arguments:
name: string
getService: retrieve service object
setService: set the remote service for the object
arguments:
connection: a <em>NetConnection</em> object
servicePath: a path to a remote service
sayHello: interface to remote method <em>sayHello( )</em>
arguments:
callback: function to handle results of the remote call
Dependencies:
com.oreilly.frdg.Result
*/
#include "com/oreilly/frdg/Result.as"
// Constructor takes one optional argument (<em>name</em>)
function User (name) {
if (arguments)
this.name = name;
}
User.prototype.getName = function ( ) {
return this.name;
};
// Set the <em>name</em> property only if the argument exists and is not blank
User.prototype.setName = function (name) {
if (name != "" && name != undefined)
this.name = name;
};
User.prototype.getService = function ( ) {
return this.service;
};
// Create remote service object as a property of <em>User</em>
User.prototype.setService = function (connection, servicePath) {
this.service = connection.getService(servicePath);
};
// Interface to remote method, <em>sayHello( )</em>
User.prototype.sayHello = function (callback, errorHandler) {
this.getService( ).sayHello(new Result(callback, errorHandler), this.name);
};The User class is extremely simple, with one argument in the constructor; two properties, each with getter/setter methods; and one public method that is used as an interface to the remote method, sayHello( ). The User class exists apart from the user interface code set up previously. The Flash UI that was set up will work with any User class that we implement in the future, as long as the API to the class remains the same (i.e., the same public properties, methods, and events).
-
You can see that the User class also requires one other class: the Result class. Create the Result.as file as follows, and save it to the same directory as the User.as file:
/*
public Result
constructor:
new Result(resultHandler, errorHandler); // Set result handler and error
handler properties
arguments:
resultHandler: function
errorHandler: function (optional)
properties:
none
methods:
onResult: method to handle remote results
arguments:
myResult: argument returned from remote call
onStatus: method to handle remote errors
arguments:
myError: argument returned from remote call in event of error
Dependencies:
none
*/
function Result (resultHandler, errorHandler) {
this.resultHandler = resultHandler;
this.errorHandler = errorHandler;
}
// Set up <em>onResult( )</em> and <em>onStatus( )</em> handlers as methods of the <em>Result</em> class
Result.prototype.onResult = function (myResults) {
this.resultHandler(myResults);
};
Result.prototype.onStatus = function (myError) {
if (this.errorHandler == "undefined") {
trace(myError.description);
} else {
this.errorHandler(myError.description);
}
};
System.onStatus = Result.prototype.onStatus;The Result class is a special responder object. The responder does not act on any of the results, and, as such, it can be used for any remote service call. You pass a callback function to the instance of the Result class when you instantiate it. In this case, we instantiated the object in the User object instance defined in Step 7:
User.prototype.sayHello = function (callback, errorHandler) {
this.getService( ).sayHello(new Result(callback, errorHandler), this.name);
}; -
Save and test the movie. It should work exactly as the procedural example.
Objects communicating: that's what OOP is all about. The user interface knows nothing of the Result class. It knows only about the User object and how to communicate with it. It depends on the User object; however, any User object that provides the same properties, methods, and events could be substituted without a problem. You'll notice that the OOP code is much wordier than the simple procedural example that does the same thing. Even so, the initial time spent modeling your application and setting up your classes is regained when you implement the application and make modifications further down the road. Modifications come easy to an OOP application.

