Selected Design Patterns: Chapter 2 - Enterprise Development with Flex

by Yakov Fain, Anatole Tartakovsky, Victor Rasputnis

Design patterns suggest an approach to common problems that arise during software development regardless of programming language. For example, when you need to ensure that your application allows only one instance of a particular class, you need to implement a singleton design pattern. If you need to pass the data between different objects, you create data transfer objects (a.k.a. value objects). There are a number of books written about design patterns and their implementation in different programming languages, including ActionScript 3.0; see ActionScript 3.0 Design Patterns by William Sanders and Chandima Cumaranatunge (O'Reilly). This chapter is not yet another tutorial on patterns. The goal of this chapter is to highlight selected patterns, as you (the developer) may implement them to take advantage of the Flex framework.

Enterprise Development with Flex book cover

This excerpt is from Enterprise Development with Flex. If you want to use Adobe Flex to build production-quality Rich Internet Applications for the enterprise, this groundbreaking book shows you exactly what's required. You'll learn efficient techniques and best practices, and compare several frameworks and tools available for RIA development -- well beyond anything you'll find in Flex tutorials and product documentation. Through many practical examples, the authors impart their considerable experience to help you overcome challenges during your project's life cycle.

buy button

While going through the examples shown in this chapter, please keep in mind that Flex is a domain-specific tool that’s aimed at creating rich UI for the Web and providing efficient communication with the server-side systems.

We realize that there are people who don’t like using the dynamic features of Action-Script, arguing that it makes the code less readable. In our opinion, there are lots of cases when dynamic features of the language can make the code concise and elegant.

All code examples from this chapter are located in two Flash Builder projects: Patterns and a Flex library project called Patterns_lib. You’ll need to import them from the code accompanying this book.

In the previous chapter, you saw that each version of Café Townsend was built implementing some of design patterns. After reading this chapter, you may want to revisit the code of Chapter 1 —you may have some new ideas about how to build yet another version of Café.

Singleton

As the name singleton implies, only one instance of such a class can be instantiated, which makes such classes useful if you’d like to create some kinds of global repositories of the data so that various objects of your application can access them. In Chapter 1 , you saw examples of their use by various architectural Flex frameworks. For example, ModelLocator from Cairngorm provides a repository for the data that was retrieved by delegates so that the views can properly display it. But to get access to the data stored in this singleton, your application class has to first get a hold of this singleton:

var model: AppModelLocator = AppModelLocator.getInstance();

After this is done, you can access the data stored in various properties of the object to which the variable model refers.

If you need a Cairngorm singleton that can communicate with the server side, write the following code:

service = ServiceLocator.getInstance().getHTTPService( 'loadEmployeesService');

Pretty soon, your application code gets polluted with similar lines of code that try to get a reference to one of the singletons.

Here’s the idea. Why not just use a singleton that already exists in any Flex application instead of introducing new ones? This is a Flex Application object that’s always there for you because it is part of the Flex framework. Thus you can be fairly sure that there is only one instance of it.

The problem is that the Application class was not created as dynamic, and you need to either extend it to act as a singleton with specific properties, or make it dynamic to be able to add to the application singleton any properties dynamically. Example 2-1 ’s dynamic class DynamicApplication is a subclass of the Flex class Application. It implements a Dictionary that allows you to register your services with the application.

Example 2-1. DynamicApplication class

package com.farata.core{
	import flash.utils.Dictionary;
	import mx.core.Application;
	public dynamic class DynamicApplication extends Application implements
		IApplicationFacade{
			public function DynamicApplication(){
			super();
		}
		public static var services:Dictionary = new Dictionary();
	
	// Consider using getter and setter if you need to override behavior 
	// but a workaround with "static" problem in Flex
		public function getService(name:String) : Object {  
			return services[name];
		}
		public function addService(name:String,value: Object): void {
			services[name] = value;
		}
		public function removeService(name:String) : void {
			delete services[name];
		}
		public function getServices() : Dictionary { 
			return services; 
		} 
	} 
}

This singleton class implements the IApplicationFacadeinterface (Example 2-2), which defines the methods to add, remove, and get a reference to the objects that are required by your application. The main reason to use the IApplicationFacade interface here is that when you typecast an Application with this interface in your code, you get Flash Builder’s “intellisense” support and compile-time error checking.

Example 2-2. IApplicationFacade interface


package com.farata.core {
    import flash.utils.Dictionary;
	public interface IApplicationFacade {
	function getService(name:String) : Object ;
	function addService(name:String,value:Object):void ;
	function removeService(name:String) : void ;
	function getServices() : Dictionary ;
    } 
} 

Note that the test program shown in Example 2-3 is no longer a regular <mx:Applica tion>, but rather an instance of the dynamic class shown in Example 2-1 and is located in the Patterns_lib project. Upon application startup, it calls the function addAllServices(), which dynamically adds myModel and myServices properties to the application object. Now any other object from the application can access this global repository just by accessing DynamicApplication.servicesfollowed by the property you are trying to reach. This is illustrated in the functions getData() and setData() used in Example 2-3 .

Example 2-3. The application Singleton.mxml


<?xml version="1.0" encoding="utf-8"?> 
<fx:DynamicApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
xmlns:fx="http://www.faratasystems.com/2009/components" 
creationComplete="addAllServices();"> 
<mx:Script>

<![CDATA[
import com.farata.core.DynamicApplication; 
import mx.core.Application; 
// Add required services to the Application object. // For illustration purposes, we'll add myModel and // myServices 
private function addAllServices() :void { 
// Add the model repository to the application object 
DynamicApplication.services["myModel"]= new Object(); 
// Add the services to the application object 
DynamicApplication.services["myServices"] = new Object(); 
} 
private function getData(serviceName:String, key:Object):Object{ 
return DynamicApplication.services[serviceName][key]; 
} 
private function setData(serviceName:String, key:Object, value:String):void{
DynamicApplication.services[serviceName][key]= new String(value); 
} 
]]> 
</mx:Script> 

<!--Adding values to myModel --> 
<mx:Button label="Add to myModel" x="193" y="59" 
click="setData('myModel',key.text, value.text)"/> 

<mx:Label x="14" y="42" text="Key" fontWeight="bold"/> 
<mx:Label x="14" y="14" fontWeight="bold" fontSize="14"> 
<mx:text> 
Add one or more key/value pairs to the object MyModel 
</mx:text> 
</mx:Label> 
<mx:Label x="91" y="42" text="Value" fontWeight="bold"/> 
<mx:TextInput x="8" y="59" id="key" width="75"/> 
<mx:TextInput x="89" y="59" id="value" width="96"/> 

<!--Retrieving the value from a Singleton. --> 
<mx:Button label="Show the value" x="8" y="122" click= 
"retrievedValue.text=getData('myModel', key.text) as String"/> 
<mx:Label x="135" y="121" width="95" id="retrievedValue" fontWeight="bold" 
fontSize="15"/> 
<mx:Label x="10" y="94" fontWeight="bold" fontSize="14"> 
<mx:text> 
Retrieve and display the value from MyModel bykey 
</mx:text> 
</mx:Label> 
</fx:DynamicApplication> 

As Figure 2-1 shows, this application displays a window in which a user can add any key/value pairs to the myModelobject located in the singleton DynamicApplication. Then you can access them by key by clicking on the button labeled “Show the value.”

The point of this exercise was to show how you can use a somewhat modified Flex Application object to create a global repository (a singleton) without the need to implement the singleton design pattern on your own.

Proxy

A proxy is an object that represents another object and controls access to it. Think of someone’s spokesperson or a secretary. If someone brings a package to a big shot, the package is taken by the secretary, who would inspect the contents and then either deliver the package to the boss or delegate its further processing to someone else (e.g., security personnel).

In object-oriented programming in general and in ActionScript specifically, you can wrap the class XYZ in mx.util.ObjectProxy, which will be a proxy that controls access to XYZ’s properties.

Let’s think of some concrete Flex examples that illustrate how proxies can control access to object properties by dispatching propertyChange events. As a matter of fact, your Flex programs that use data binding already implement a similar mechanism of event notifications under the hood.

Data binding is a very useful technique that substantially increases the productivity of Flex developers. If you start the declaration of a variable or a class with the meta tag [Bindable], all of a sudden the variable starts emitting events about all changes that can happen to it. The syntax to make this happen is very simple:

	[Bindable]
	var lastName:String;
	

How does this event notification mechanism get engaged by simply adding the magic word [Bindable]? You are all seasoned programmers and don’t believe in the tooth fairy. Someone has to write the code that will dispatch events when the value of the property lastName changes. The compiler does it behind the scenes by creating a wrapper class that implements a getter and setter for the lastName property and then uses that wrapper class. The setter contains the code-dispatching propertyChange event, which carries such useful information as old and new values of the property that’s being modified.

But you don’t always have to depend on the Flex compiler when you need to create an event notification or any other customization or generalization outside of the original class. For that, you create a proxy on your own using the class ObjectProxy as shown in the following examples.

To illustrate the work of ObjectProxy, we have created a small application that changes the values of the properties of the class Person wrapped into an instance of Object Proxy (Example 2-4).

Example 2-4. Class Person


package com.farata{
	public dynamic class Person {
	public var lastName:String="Johnson";
	public var salary:Number=50000;
	} 
} 

The application code illustrating the use of ObjectProxy is shown in Example 2-5.

Example 2-5. PersonProxy.mxml


<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml 
creationComplete="personProxy.addEventListener(PropertyChangeEvent.PROPERT 
Y_CHANGE, changeHandler)" 
layout="absolute"> 

<mx:Script> 
<![CDATA[ 
import mx.events.PropertyChangeEvent; 
import mx.utils.ObjectProxy; 
import com.farata.Person; 

var person:Person = new Person; 
var personProxy:ObjectProxy = new ObjectProxy(person); 

function changeHandler(event:PropertyChangeEvent):void{

log.text+="event.kind: "+ event.kind + " property :" + event.property +" old value:" + event.oldValue + " new value: " + event.newValue +"\n";
}

]]> </mx:Script> <mx:Button x="46" y="31" label="Increase Salary by $3K" click="personProxy.salary += 3000;"/>

<mx:Button x="211" y="31" label="Change Last Name toMcCartney" click="personProxy.lastName='McCartney'"/> <mx:Button x="428" y="31" label="Directly Change Last Name to Allen" click="person.lastName='Allen';"/> <mx:Label x="47" y="61" text="Change Log" fontWeight="bold" fontSize="14"/> <mx:TextArea id="log" x="46" y="91" width="600" height="250" fontWeight="bold" fontSize="14"/> <mx:Button x="50" y="357" label="Add pension property " click="personProxy.pension='yes'"/> <mx:Button x="216" y="357" label="Delete pension property" click="delete personProxy.pension"/> <mx:Label text="{personProxy.lastName}" x="428" y="359" fontSize="14" fontWeight="bold"/> </mx:Application>

There is one line in PersonProxy.mxml that wraps up the instance of the class Person into an ObjectProxy:

var personProxy:ObjectProxy = new ObjectProxy(person);

This is all it takes to ensure that all changes to PersonProxy will be announced—the PropertyChangeEvent will be triggered, and as you’ve added an event listener to the instance of the Person class, notifications are being sent about every little change that happens to that instance.

Figure 2-2 shows the output generated by this event handler after six sequential clicks: top buttons one, two, three, two, followed by the clicks on the two buttons at the bottom.

After the first click, the salary is increased by $3K, and the ObjectProxy notification conveniently offers the old and the new values of the property salary. The click on the second button changes the last name from Johnson to McCartney. The click on the third button quietly changes the last name from McCartney to Allen, because you applied this change not to the personProxy instance, but directly to the Person. To make sure that the value has been changed, you click button two again, which goes through the ObjectProxy and properly reports that the name has been changed from Allen to McCartney.

The two buttons at the bottom just illustrate that because the class Person has been declared as dynamic, you can add and remove properties on the fly and the person Proxy will properly report on these events, too.

Notice the addition of property change notifiers to the class Person without changing a single line of this code. This technique may also become handy when you don’t have the source code of a class but need to enable property change notifications. In other words, you can enable data binding on a class that you did not create. If you’ve had a chance to deal with aspect-oriented programming, this may sound familiar— you add the functionality to the application without changing the application objects.

To give this example more business context, create a custom class MyPersonProxy by subclassing ObjectProxyand adding some application logic to it. If the salary of a person increases over $55K, say, that employee becomes entitled to the pension in the amount of 2 percent of the salary. You want to add this functionality without touching the code of the class Person.

When you create a subclass of ObjectProxy, you’ll be overriding at least two methods: getProperty() and setProperty() from the namespace flash_proxy, the reason being that if you write MyPersonProxy.lastName="McCartney", this object will call its own method setProperty("lastName", "McCartney") and if you want to intercept this call and add some additional processing to it, you just add it to the overridden method setProperty(). The method getProperty() is being called when you are trying to read a property of a Proxyobject. The Proxyclass defines a number of other useful functions, but discussing them is out of the scope of this book.

Our class MyPersonProxy(see Example 2-6) is derived from ObjectProxy. Its constructor receives and stores the instance of the Person class, and its setProperty() method is overridden to add a new property pension as soon as the salary of the person goes over $55K. Obviously, you can use any business logic to intercept the moment when some “important” properties are being changed in your application and react accordingly.

Example 2-6. MyPersonProxy.as


package com.farata { 
import mx.utils.ObjectProxy; import flash.utils.*; 
use namespace flash_proxy;
	public dynamic class MyPersonProxy extends ObjectProxy {
	    // The object to wrap up
	    private var person:Person;
	    public function MyPersonProxy(item:Person) {
	        super(item);
	        person=item;
	    }
	    flash_proxy override function setProperty(name:*, value:*):void { 
	    if ( name == 'salary'&& value>55000) {
	        // add a new property to this instance of the
                // class Person, which can be used in the calculations
                // of the total compensation
	        setProperty("pension", 0.02); 
	    } 
	    super.setProperty(name, value); 
	    } 
	} 
} 

In Example 2-7 , the program CustomProxy illustrates the use of the MyPersonProxy class.

Example 2-7. CustomProxy.mxml

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 

creationComplete="personProxy.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, changeHandler)"> <mx:Script> <![CDATA[ import mx.events.PropertyChangeEvent;
//import mx.utils.ObjectProxy; 
import com.farata.MyPersonProxy; import com.farata.Person;
var person:Person = new Person; var personProxy:MyPersonProxy = new MyPersonProxy(person);
function changeHandler(event:PropertyChangeEvent):void { 
log.text+="event.kind: "+ event.kind + " property :" + event.property + " old value:" + event.oldValue + " new value: " + event.newValue +"\n";
}
]]>
</mx:Script>
<mx:Button x="46" y="31" label="Increase Salary by $3K"

click="personProxy.salary += 3000;"/>
<mx:Label x="47" y="61" text="Change Log" fontWeight="bold" fontSize="14"/>
<mx:TextArea id="log" x="46" y="91" width="600" height="250" fontWeight="bold" fontSize="14"/>
</mx:Application>
Run this program and you’ll see the output in Figure 2-3 after making three clicks on the Increase Salary button. The second click properly reports the addition of the pension property as well as the salary change. The third click doesn’t report the change—the pension property was being assigned the same value on the third click; the proxy did not dispatch a PropertyChangeEvent regarding the pension.

Here’s another example, RemoteObject:

<mx:RemoteObject id="ro" destination=quotMyEmployees" />

What exactly happens when you call a method on a remote destination that goes by the nickname MyEmployees?

MyEmployees.getEmployees();

Flex is client software that does not need to know what powers the MyEmployeesfunction has on the server side. Is there a ColdFusion or a Java object that has the function getEmployees() implemented? Flex doesn’t need to know or care.

In the Java world, if you want to implement client/server communication using Remote Method Invocation between objects located in different Virtual Machines (VMs), you’d have to explicitly define a stub class on the client (a proxy) that represents its peer skeleton class on the server on the remote VM.

Flex spares you from creating stubs, automatically wraps these remote calls into proxy objects, and internally uses the invoke() method call to pass the name of the remote method and its parameters.

Flex’s ability to declaratively define a reaction to the changes in the data or components state greatly simplifies programming and reduces errors related to low-level coding.

In order for binding to work, you need to make sure that the Flex framework knows when the data changes. Unlike most dynamic language implementations, ActionScript

3.0 is built for speed and heavily utilizes direct access to properties and methods. In this situation, the only way for data to notify the world about the changes is to embed the code to fire change events.

The Flex compiler helps in a big way by introducing [Bindable] and [Managed] tags. If you prefix your variable with the [Bindable] tag, the compiler does the following:

  • Inspects every public property and setter of your variables class and generates wrapper getters/setters that add event notification
  • References these getters/setters instead of original properties every time a “bindable” property is being used

Having a wrapper with a setter and a getter is technically the same as creating a proxy; that is, the setter can include and execute additional code every time the value of this specific property changes. Obviously, it does not work with untyped data coming from the server. Such data is converted to a dynamic Object type. The problem is alleviated a bit by the fact that the Flex framework would automatically wrap the Object in the ObjectProxy if the default property of the RemoteObject makeObjectBindable=true were not modified.

However, Flex will wrap only the top level and not the individual array members, making changes to those undetectable. For example, say you are passing a set of the objects from a remote Java assembler class that sends data transfer objects (DTOs) that may include an array property. These DTOs will eventually become rows in a DataGrid. The changes to these array elements are not going to dispatch change events unless you explicitly wrap each array element in the ObjectProxy, for example:

private function onResult(r:ResultEvent) : void {
	var quotes:ArrayCollection = r.result.quotes;
	var wrappedQuotes = new ArrayCollection();
	for each (var quote in quotes)
	wrappedQuotes.addItem(new ObjectProxy(quote))
	view.dataProvider = wrappedQuotes;
} 

ObjectProxy can make the code development process more productive, but keep in mind that you are going to pay a high price for this as it introduces additional processing during the runtime—dynamic objects are much slower than strongly typed ones. Even more important, because of automatic wrapping the code might dispatch an event on each data change. Data binding is great, but if you need to process larger data sets and really need to use data binding, consider strongly typed classes that will support [Bindable] on the class members level and even optimize dispatching of the events. If you are doing massive updates of data, using ObjectProxy or any other form of data binding can substantially affect performance and the ability to trace your applications.

The bottom line is this: implement the proxy design pattern whenever you need to monitor the changes that are happening to a particular object. Yet another advantage of using proxies is that you can modify the behavior of an object without the need to modify its code.

Mediator

Almost any complex screen of a business application consists of a number of containers and components. The era of developers being responsible for both functionality and visuals is coming to an end, and a large portion of the enterprise RIA is created in a collaboration between professional UI designers and developers.

Typically, a UI designer gives you a UI wireframe that he puts together using one of the design tools. In the best-case scenario, the UI designer knows how to use Flash Builder in the design mode or even uses Adobe Flash Catalyst to autogenerate MXML for the UI. But even in this case, you, the developer, will need to rip this code apart and decide what components to build to create this view and how they are going to communicate with each other—you need to refactor the code.

Let’s see how you can arrange communication between custom Flex components. The diagram in Figure 2-4 consists of a number of nested components and containers that are numbered for easier reference.

For simplicity and better abstraction, this example does not use the actual components, like panels and drop-downs, but you can extrapolate this image onto the wireframe of the actual view you are about to start developing.

A simple (but wrong) approach is to just put all these components in one container (number 1 in Figure 2-4), program the business logic and communications among these components, and be done with it. This would produce a monolithic application with tightly coupled components that know about each other and where removal of one component would lead to multiple code changes in the application. Talk about strings attached!

The better approach is to create loosely coupled custom components that are self-contained, do not know about one another’s existence, and can communicate with the “outside world” by sending and receiving events.

Adobe Flex was designed for creating event-driven applications, and it has a good component model, allowing you to create custom components if need be. But after custom components are designed, they need to communicate with each other. This section covers the use of the Mediator design pattern as it applies to UIs created with Flex.

Think of a single Lego from a Lego toy set. Now, some kid (i.e., the mediator) may decide to use that Lego piece to build a house. Tomorrow, the mediator may decide to use that same Lego piece in a boat.

In the diagram from Figure 2-4 , containers play the role of the mediators. The top-level mediator is the container marked as 1, which is responsible for making sure that the components 2, 3, and 6 can communicate if need be. On the other hand, the number 2 is a mediator for 4 and 5. The number 3 is the mediator for 7 and 8.

Being a mediator is a very honorable mission, but it comes with responsibilities. The mediator must listen for events from one of the Lego parts and possibly fire an event on the other one(s).

For example, if you are building an online store, the number 6 can be a component where you select an item to purchase, the number 4 can be the button named Add to Shopping Cart, and the number 5 can be a shopping cart.

Let’s forget about the number 6 for a moment and examine the content of the mediator, number 2. It contains the button 4, which has a specific look and feel and can do just one thing—broadcast a custom event called AddItemClicked. To whom? To whomever’s interested in receiving such an event. So expect to have the line:

dispatchEvent(new Event("AddItemClicked"))

somewhere inside the code of the component 4.

Because mediator number 2 is interested in receiving this event from number 4, it will define an event listener for such an event, which will receive the event and in turn will dispatch another event right on the number 5:

addEventListener("AddItemClicked", addItemClickedEventHandler)
...
private function addItemClickedEventHandler ():void {
	Number5.dispatchEvent(new Event("Add2ShoppingCart"));
}

In this pseudocode, the mediator is choreographing the show by defining how its components will communicate.

We’d like to stress that in the previous example, the number 4 is like shooting an event up into the sky—anyone who wants to can listen. On the other hand, the number 5 is just sitting quietly and listening to the incoming event. From whom? It has no idea. This is what loose coupling of components means. The number 4 mediator does not know about the number 5, but they talk anyway through the mediator.

But as a developer of this screen, you have to take care of mediator-to-mediator communications as well. For instance, if the number 6 is a widget where you can select your Sony TV, the mediator 1 will be notified about it and need to talk to the mediator 2, which in turn will arrange the flow between 4 and 5.

Let’s build a concrete example showing how to build these components and establish their communication using the Mediator design pattern. This is an oversimplified trading screen to buy/sell equities at the stock market. This application will have price and order panels. In the real world, the price panel would get an external feed about the prices and deals for all securities that are being traded on the market.

The web designer might give you the two screenshots shown in Figures 2-5 and 2-6 (we hope that your designer has better artistic talent than we do).

This is a pretty simple window. You will design it as two components that communicate with each other without having any knowledge about each other. The Flex application will play role of the mediator here. When the user sees the right price to buy or sell IBM shares, she clicks on the bid or ask price; this action will create a custom event with the current data from the price panel bid and ask prices, the stock symbol, and whether this is a request to buy or sell.

In brokerage, bid means the highest price that the trader is willing to pay for the stock or other financial product, and ask is the lowest price the seller is willing to accept.

Example 2-8 shows the PricePanel component. It has three public variables—symbol, bid, and ask. When the trader clicks on one of the numbers in the price panel, the code creates an instance of the custom event of the type OrderEvent.PREPARE_ORDER_EVENT, and all public variables and the name of the requested operation are nicely packaged inside of this event. Then the PricePanel component dispatches this event. To whom? It has no idea.

Example 2-8. PricePanel.mxml

<?xml version="1.0" encoding="utf-8"?> 
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="230" height="100" 

backgroundColor="#D4E5D9">

<mx:TextInput x="0" y="-1" width="228" backgroundColor="#0DF113"
text="{symbol}" fontWeight="bold" fontSize="19" textAlign="center"/>
<mx:Label x="39" y="31" text="Bid" fontWeight="bold" fontSize="14"/>
<mx:TextArea x="1" y="49" width="109" height="47" backgroundColor="#EBF4A2"

text="{bid}" fontSize="22" fontStyle="normal" fontWeight="bold"
click="placeOrder(true)" editable="false" /> 

<mx:Label x="154" y="31" text="Ask" fontWeight="bold" fontSize="14"/> <mx:TextArea x="118" y="49" width="109" height="47"
backgroundColor="#A2BFF4" text="{ask}" fontSize="22" fontStyle="normal" fontWeight="bold" click="placeOrder(false)" editable="false"/> <mx:Script>
<![CDATA[
	import com.farata.events.OrderEvent;

	public var symbol:String;
	[Bindable]
	public var bid:String;
	[Bindable]
	public var ask:String;

 // Dispatch the OrderEvent to be picked by a Mediator<
private function placeOrder(buy:Boolean):void { 
	dispatchEvent(new OrderEvent(OrderEvent.PREPARE_ORDER_EVENT,symbol,bid,ask,buy)); 
	} 
]]> </mx:Script>
</mx:Canvas>

And Example 2-9 shows the definition of the custom OrderEvent. In this version, it declares several variables for storing the order data, but the section on data transfer objects simplifies this event a little bit.

Please note that this event defines two event types. The OrderEvent of the type PREPARE_ORDER_EVENT is being sent by the PricePanel; the mediator receives it and forwards it to the OrderPanel as PLACE_ORDER_EVENT.

Example 2-9. OrderEvent.as

package com.farata.events{
import flash.events.Event; public class OrderEvent extends Event {
public var symbol:String; public var bid:String; public var ask:String; public var buy:Boolean; public var eventType:String;
	public static const PREPARE_ORDER_EVENT:String ="OrderEvent"; public static const PLACE_ORDER_EVENT:String="PlaceOrderEvent"; 

public function OrderEvent(eventType:String, symbol:String, bid:String, ask:String, buy:Boolean ) { super(eventType,true, true); // let it bubble this.symbol=symbol; this.bid=bid; this.ask=ask; this.buy=buy; this.eventType=eventType; } override public function clone():Event { return new OrderEvent(eventType,symbol, bid, ask,buy); } } }

The OrderPanel shown in Example 2-10 listens to the event of the OrderEvent.PLACE_ORDER_EVENT type. When this event arrives (this panel has no idea from whom), the OrderPanel populates the fields with the order data extracted from the event object.

Example 2-10. OrderPanel.mxml

<?xml version="1.0" encoding="utf-8"?> 
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" 
width="230" height="100" backgroundColor=quot;#4CF3D2" creationComplete=
"this.addEventListener(OrderEvent.PLACE_ORDER_EVENT,orderEventHandler)">

	<mx:Text id="sym" x="0" y="10" width="61" fontWeight="bold" fontSize="19"/>
	<mx:Text id="operation" x="81" y="10" fontSize="19"/>
	<mx:Text id="price" x="48" y="37" width="91" fontWeight="bold" fontSize="16"/>
	<mx:Label x="5" y="65" text="Qty:" fontSize="19" fontWeight="bold"/>
	<mx:TextInput id="qty" x="70" y="69" width="71" text="100" fontSize="16" selectionBeginIndex="0" selectionEndIndex="5"/>
	<mx:Button id="go" x="147" y="7" label="GO!" height="60" width="74" fontSize="22" click="placeOrder()" enabled="false"/>
	<mx:Button x="148" y="75" label="Cancel" width="72"

        <mx:Script>
	<![CDATA[
	import mx.controls.Alert;
	import com.farata.events.OrderEvent;

	private function orderEventHandler(evt:OrderEvent) {
		go.enabled=true;
		sym.text=evt.symbol;
	operation.text=evt.buy?"Buy":"Sell";
	price.text=operation.text=="Buy"?evt.bid:evt.ask;
	qty.setFocus();

	}
	private function placeOrder():void{
	Alert.show(operation.text + " " + qty.text +
	" shares of " + sym.text +
	" at" + price.text + " per share", "Placing order");

 	// call a remote service to place this order
	}

        private function cancelOrder():void{
	sym.text="";
	operation.text="";
	price.text="";
	go.enabled=false;

        }
	]]>
	</mx:Script> 

</mx:Canvas>

Here comes the mediator (Example 2-11), which includes two components— PricePanel and OrderPanel. The mediator listens to the event from the PricePanel and forwards it to the OrderPanel in the function orderEventHandler.

Example 2-11. A test application: Trading1.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:comp="com.farata.components.*" backgroundColor="white" applicationComplete=
"this.addEventListener(OrderEvent.PREPARE_ORDER_EVENT,orderEventHandler)"> 
<mx:Label text="Price Panel" y="4" height="23" x="69" fontSize="16" 

fontWeight="bold"/> 
<mx:Label text="Order Panel" y="4" height="23" x="290" fontSize="16" 

fontWeight="bold"/> 
<comp:PricePanel symbol="IBM" bid="117.45" ask="117.48" y="31" x="7"/> 
<comp:OrderPanel id="ordPanel" x="245" y="30"/> 

<mx:Script> <![CDATA[ import mx.controls.Alert;
import com.farata.events.OrderEvent;
private function orderEventHandler(evt:OrderEvent):void{
// The mediator decides what to do with the received event. 
// In this case it forwards the order received 
// from PricePanel to OrderPanel
var orderEvt: OrderEvent= new
OrderEvent(OrderEvent.PLACE_ORDER_EVENT,
evt.symbol, evt.bid, evt.ask, evt.buy);
ordPanel.dispatchEvent(orderEvt);
}
]]> 
</mx:Script> 
</mx:Application>

Once again, components don’t know about one another and can be reused in another context, too.

The mediator is one of the most useful patterns for any programming environment that includes components communicating with each other—even more so if you program in an event-driven environment such as Flex. Use this pattern before implementing the UI design. Identify your mediators and custom reusable components and decide what events these components will broadcast or listen to.

After you have made all these decisions, select the format of the data that will travel between the components. This is where the data transfer pattern comes into the picture.

Data Transfer Object

Data transfer objects are also known as value objects (VOs) and are used for data exchanges between various application components, which can be either colocated in the same process or on remote computers. These DTOs can even be written in different programming languages, for example, Java and ActionScript.

First, modify the application from the previous section and encapsulate the order details in a simple OrderDTO that will be placed in the event object and will happily travel between price and order panels. When this is done, you will spend some time with more advanced DTOs that you may want to use in Flex remoting.

Example 2-12 is a simple OrderDTO.as that will be passed between the price and order panels.

Example 2-12. OrderDTO.as


package com.farata.dto {
	// [RemoteClass] meta tag goes here if this DTO
	// is used in Flex Remotin
	[Bindable]
	public class OrderDTO {
		public var symbol:String;
		public var bid:String;
		public var ask:String;
		public var buy:Boolean; 
		//a buy/sell flag
		public function OrderDTO(symbol:String, bid:String, ask:String,
		buy:Boolean=false) {
			this.symbol=symbol;
			this.bid=bid;
			this.ask=ask;
			this.buy=buy;		
		}
	} 
}

In Example 2-13 ’s second version of the price panel, add a function startDataFeed(), emulating the real data feed that may be bringing the market data to the pricing panel. Please note that the PricePanel now displays the data from this “external” feed by binding the UI controls to the properties of the currentData object “received” from a remote server.

Example 2-13. PricePanel2.mxml


<?xml version="1.0" encoding="utf-8"?> 
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="230" height="100" 
backgroundColor="#D4E5D9">

<mx:TextInput x="0" y="-1" width="228" backgroundColor="#0DF113"

text="{currentData.symbol}" fontWeight="bold" fontSize="19" 

textAlign="center"/> <mx:Label x="39" y="31" text="Bid" fontWeight="bold" fontSize="14"/> <mx:TextArea x="1" y="49" width="109" height="47" backgroundColor="#EBF4A2"
text="{currentData.bid}" fontSize="22" fontStyle="normal" fontWeight="bold" click="placeOrder(true)" editable="false" creationComplete="startDataFeed()"/>
<mx:Label x="154" y="31" text="Ask" fontWeight="bold" fontSize="14"/>

<mx:TextArea x="118" y="49" width="109" height="47" backgroundColor="#A2BFF4" text="{currentData.ask}" fontSize="22" fontStyle="normal" fontWeight="bold" click="placeOrder(false)" editable="false"/> <mx:Script> <![CDATA[ import com.farata.dto.OrderDTO; import com.farata.events.OrderEvent2; [Bindable] private var currentData:OrderDTO; private function startDataFeed():void { // the code for getting the real data feed goes here currentData = new OrderDTO("ADBE","40.47", "40.51"); } // Create the OrderEvent and place the DTO there // Dispatch the event to be picked by a mediator private function placeOrder(buy:Boolean):void { currentData.buy=buy; // set the flag to buy or sell dispatchEvent(new OrderEvent2(OrderEvent2.PREPARE_ORDER_EVENT,currentData)); } ]]> </mx:Script> </mx:Canvas>

In Example 2-14 , the function placeOrder()dispatches the OrderEvent2with a packaged DTO inside. There is no need to declare multiple variables, as this was done in Example 2-9 .

Example 2-14. OrderEvent2.as

package com.farata.events{
import com.farata.dto.OrderDTO; import flash.events.Event;
	public class OrderEvent2 extends Event {
	public var orderInfo: OrderDTO; public var eventType:String;
	public static const PREPARE_ORDER_EVENT:String ="OrderEvent"; public static const PLACE_ORDER_EVENT:String ="PlaceOrderEvent";
		public function OrderEvent2(eventType:String, order:OrderDTO ) { 
		super(eventType,true, true); // let it bubble this.orderInfo=order; // store the orderDTO
		this.eventType=eventType;
		} 
		
		override public function clone():Event { 
		return new OrderEvent2(eventType,orderInfo); 
		} 
	} 
}

The new version of your driving application, Trading2.mxml (Example 2-15), does not assign the symbol, bid, and ask values to the price panel, as this was done for simplicity in Example 2-11 . Now the PricePanel is being populated by its own data feed.

Example 2-15. The driving application, Trading2.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:comp="com.farata.components.*" backgroundColor="white" applicationComplete="this.addEventListener(
OrderEvent2.PREPARE_ORDER_EVENT,orderEventHandler)" >
<mx:Label text="Price Panel" y="4" height="23" x="69" fontSize="16" 

fontWeight="bold"/> 
<mx:Label text="Order Panel" y="4" height="23" x="290" fontSize="16" 

fontWeight="bold"/> 
<comp:PricePanel2 y="31" x="7"/> 
<comp:OrderPanel2 id="ordPanel" x="245" y="30"/> 
<mx:Script>

<![CDATA[
import mx.controls.Alert;
import com.farata.events.OrderEvent2;

private function orderEventHandler(evt:OrderEvent2):void{
 // The mediator decides what to do with the received event 
// In this case it forwards the order received 
// from PricePanel to OrderPanel
var orderEvt: OrderEvent2= new OrderEvent2(OrderEvent2.PLACE_ORDER_EVENT,evt.orderInfo); 
ordPanel.dispatchEvent(orderEvt);
}
]]> 
</mx:Script> 
</mx:Application>

Even though you haven’t yet seen the code of the OrderPanel2, you can still use it, as long as its API is known—in this case, you know that it listens to the OrderEvent2. As a matter of fact, in many cases you’ll be using components without having any knowledge about how they operate inside.

But to go easy on you, Example 2-16 shows you the source code of OrderPanel2.mxml, which receives the OrderEvent2, extracts the OrderDTO, and populates its UI controls.

Example 2-16. OrderPanel2.mxml

<?xml version="1.0" encoding="utf-8"?> 
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="230" height="100" 
backgroundColor="#4CF3D2" creationComplete="this.addEventListener(OrderEvent2.PLACE_ORDER_EVENT,orderEventHandler)">  

<mx:Text id="sym" x="0" y="10" width="61" fontWeight="bold" fontSize="19"/>
<mx:Text id="operation" x="81" y="10" fontSize="19"/>
<mx:Text id="price" x="48" y="37" width="91" fontWeight="bold" fontSize="16"/>
<mx:Label x="5" y="65" text="Qty:" fontSize="19" fontWeight="bold"/>
<mx:TextInput id="qty" x="70" y="69" width="71" text="100" fontSize="16" selectionBeginIndex="0" selectionEndIndex="5"/>

<mx:Button id="go" x="147" y="7" label="GO!" height="60" width="74" fontSize="22" click="placeOrder()" enabled="false"/> <mx:Button x="148" y="75" label="Cancel" width="72" click="cancelOrder()"/> <mx:Script> <![CDATA[ import com.farata.dto.OrderDTO; import mx.controls.Alert; import com.farata.events.OrderEvent2; private var orderInfo:OrderDTO; // the order packaged in the DTO private function orderEventHandler(evt:OrderEvent2){ go.enabled=true; orderInfo=evt.orderInfo; // extract the DTO from the event object sym.text=orderInfo.symbol; operation.text=orderInfo.buy?"Buy":"Sell"; price.text=operation.text=="Buy"?orderInfo.bid:orderInfo.ask; qty.setFocus(); }

private function placeOrder():void{ Alert.show(operation.text + " " + qty.text + " shares of " + sym.text +" at" + price.text + " per share", "Placing order"); // call a remote service to place this order }

private function cancelOrder():void{ sym.text=""; operation.text=""; price.text=""; go.enabled=false; }

]]> </mx:Script> </mx:Canvas>

Examples 2-12 through 2-16 illustrated an application that used a DTO as a sort of exchangeable currency in the interaction between colocated Flex components.

But DTOs also play an important role during the exchange of data with the server-side application using Flex remoting or Data Management Services. In such enterprise applications, the server-side team provides a DTO coded in one of the programming languages (this example uses Java), and the Flex team has to provide a similar Action-Script DTO.

Flex RemoteObjector DataServiceclasses will serialize/deserialize these DTOs into each other, regardless of which direction they travel.

If you don’t define DTOs on the Flex side, the data will be wrapped into ObjectProxy instances, which has a negative effect on performance. If you do, annotate Flex DTOs with the [RemoteClass...] meta tag or via the registerClassAlias() function call.

We highly recommend using strongly typed data transfer objects, as opposed to dynamic objects or XML for data exchange between the client and server tiers. If you are working with a Java Server, make your Java (methods) accept/return custom classes and not generic map objects.

The following list gives you some generic recommendations about creating DTOs that are meant for communication with a remote subsystem, and then offers a solution that can automate the process of creating ActionScript DTOs from their Java peers.

  • Define similar classes in Java and ActionScript languages.
  • If you envision dynamic updates to the data on the client (e.g., the data feed of new stock prices constantly updating the data), declare these classes with the meta tag [Bindable]. Use collections of these bindable instances as data providers for Flex List-based controls like DataGrid, and Flex will ensure that all changes to the data will be reflected by the visual control. Remember, the [Bindable] meta tag results in autogeneration of the code dispatching events on every property change.

    Use an ArrayCollectionof such bindable DTOs as a dataProviderin your DataGrid, List, and similar components. Imagine a collection of objects with complex structure, with class variables of non-primitive data types—for example, a collection of Employee objects in which each object has a variable of type WorkHistory, which is a class with its own properties. If a variable declared in the WorkHistory class gets modified, the collection of Employee objects won’t know about this change unless you explicitly dispatch the propertyChange event.
  • Make sure that both server-side and client-side DTOs provide a unique property uuid. Flex uses this property to uniquely identify the data elements of the List-based controls. You will find numerous uses for this property, too.

    For instance, instead of sorting orders by the DTO’s property symbol, you’d sort by symbol and uuid. In this case, the autogenerated hash value of each DTO will be unique for each record, which will result in better performance.
  • Don’t try to intercept the changed values on the visual controls (a.k.a. View). This task belongs to the data layer (a.k.a. Model).
  • Consider replacing each public property with the getter and setter. This will allow you to have more control over the modifications of these properties. You can add code to these setters/getters that will intercept the action of data modification and perform additional processing based on what’s being changed. Then, the setter can dispatch the event PropertyChange as illustrated in this code snippet:
    [Bindable(event="propertyChange")]

    public dynamic class OrderDTO extends EventDispatcher {

    private var _bid:Number;

    public function set bid( value : Number):void { var oldValue:Object = _bid; if (oldValue !== value) { lastPrice = value; dispatchUpdateEvent("bid", oldValue, value); } } public function get bid() : String{ return _bid; } private function dispatchUpdateEvent(propertyName:String, oldValue:Object, value:Object):void { dispatchEvent( PropertyChangeEvent.createUpdateEvent(this, propertyName, oldValue, value)); } }

    This is yet another technique (remember wrapping up an object in a proxy?) for customizing the behavior of the objects when the data is being changed. Imagine that you need to create your own version of a data management service and want to maintain a collection of changed objects that remember all modifications in a DataGrid that uses a collection of OrderDTO objects as a data provider. You can maintain a collection of changed objects that remember all old and new values.

    There’s a difference between the [Bindable(event="propertyChange")] and [Bindable]meta tags. The former syntax instructs the Flex compiler to generate code watching the propertyChange events. The latter syntax forces the Flex compiler to generate the event—it replaces the property with a setter/getter pair in which the setter’s role is to dispatch the event. But if your code has taken care of event dispatching already, you may wind up with events being dispatched twice!
  • Over your project’s life span, you will see many additional uses for DTOs: custom serialization and custom toString() and toXML() methods, for example.
  • Create a basic OrderDTO as in Example 2-12 and subclass it. This way, the superclass OrderDTO maintains its original structure while its subclass allows you to add some new functionality like notifying a third party about properties’ changes or adding new properties like total order amount, which is a result of the multiplication of total shares by price per share:

    
    [Bindable(event="propertyChange"]
    public function get totalOrderAmount():Number {
    	return price*totalShares; 
    } 
    

If you are creating DTOs for the data exchange between Java and ActionScript classes using subclassing, both ActionScript classes will have the meta tag [RemoteClass] pointing to the same Java DTO. This won’t be an issue; Flex is smart enough to use the subclass for serialization.

In the real world, an enterprise project’s Flex and Java developers often belong to different teams and if Java folks change the structure of their DTOs, Flex developers need to ensure that the structure of their classes is updated accordingly. There are different ways of automating this process, as shown in Example 2-17 .

DTO2Fx is a free plug-in that’s available at http://www.myflex.org . It generates ActionScript DTO classes using the subclassing technique described earlier.

Consider the Java DTO in Example 2-17 .

Example 2-17. Annotated OrderDTO2.java


package com.farata.dto; 
import com.farata.dto2fx.annotations.FXClass; 

@FXClass 
publicclass OrderDTO2 { 
public String symbol; 
public String bid; 
public String ask; 
public Boolean buy; 

	public OrderDTO2(String symbol, String bid,String ask, Boolean buy) {
	
	this.symbol=symbol;
	this.bid=bid;
	this.ask=ask;
	this.buy=buy;
	} 
}

The DTO2Fx plug-in uses Java annotations in the process of generating ActionScript classes, and @FXClass is such an annotation. The rest of the process is simple. As soon as you create or modify this class, it automatically regenerates a couple of ActionScript classes: _OrderDTO2.as and OrderDTO2.as. You can find more details about this process in the User Guide of DTO2Fx, but for now just examine the generated code in Example 2-18.

Example 2-18. Superclass _OrderDTO2.as

package com.farata.dto {
	import mx.events.PropertyChangeEvent;
	import flash.events.EventDispatcher; import mx.core.IUID; import mx.utils.UIDUtil;
	/* [ExcludeClass] */ 
	public class _OrderDTO2 extends flash.events.EventDispatcher implements mx.core.IUID {
	/* Constructor */
		public function _OrderDTO2():void {
		 super();
		} 
	
		// implementors of IUID must have a uid property
		private var _uid:String;
		[Transient]
		[Bindable(event="propertyChange")]
		public function get uid():String {
		
			 // If the uid hasn't been assigned a value, just create a new one.
			if (_uid == null) {
			 _uid = mx.utils.UIDUtil.createUID();
			
			}
			return _uid;
		}
		
		public function set uid(value:String):void {
			const previous:String = _uid;
			if (previous != value) {
		
				_uid = value;
				dispatchEvent( mx.events.PropertyChangeEvent.createUpdateEvent( this, "uid", previous, value));
			}
		} 
		
		/* Property "ask" */
		private var _ask:String;
		[Bindable(event="propertyChange")]
		public function get ask():String {
		
			return _ask;
		}
		public function set ask(value:String):void {
		
		const previous:String = this._ask;
			if (previous != value) {
				_ask = value;
				
				const ev:mx.events.PropertyChangeEvent =
				mx.events.PropertyChangeEvent.createUpdateEvent(
 this, "ask", previous, _ask);
				dispatchEvent(ev);
			
			}
		} 
		
		/* Property "bid" */
		private var _bid:String;
		[Bindable(event="propertyChange")]
		public function get bid():String {
			return _bid;
		}
		public function set bid(value:String):void {
		
			const previous:String = this._bid; 
			if (previous != value) { 
				_bid = value; 
				constev:mx.events.PropertyChangeEvent = mx.events.PropertyChangeEvent.createUpdateEvent( this, "bid", previous, _bid); dispatchEvent(ev); 
			} 
		}
		/* Property "buy" */

private var _buy:Boolean;

[Bindable(event="propertyChange")] public function get buy():Boolean { return _buy; } public function set buy(value:Boolean):void { const previous:Boolean = this._buy; if (previous != value) { _buy = value; constev:mx.events.PropertyChangeEventmx.events.PropertyChangeEvent.createUpdateEvent(this, "buy", previous, _buy );

dispatchEvent(ev); } } /* Property "symbol" */ private var _symbol:String; [Bindable(event="propertyChange")] public function get symbol():String { return _symbol; } public function set symbol(value:String):void { const previous:String = this._symbol; if (previous != value) { _symbol = value; const ev:mx.events.PropertyChangeEvent = mx.events.PropertyChangeEvent.createUpdateEvent( this, "symbol", previous, _symbol); dispatchEvent(ev); } } } }

Example 2-18 is a superclass that will always be regenerated by DTO2Fx anytime the Java class changes. This class has a unique object identifier (uid) and includes getters and setters that will dispatch propertyChange events when the time comes.

The code of the class OrderDTO2 is shown in Example 2-19 . This class is generated only once and is a subclass of _OrderDTO2.as. This is a place for an application developer to add application-specific customization, such as the addition of new properties and/ or functions. This class will never be overridden by DTO2Fx, regardless of what was changed in OrderDTO2.java.

Example 2-19. Subclass OrderDTO2.as

package com.farata.dto {
	[RemoteClass(alias="com.farata.dto.OrderDTO2")]
	public class OrderDTO2 extends com.farata.dto._OrderDTO2 {
		/* Constructor */
		public function OrderDTO2():void { 
			super(); 
		} 
	} 
}

We hope that our message to you is clear now: the use of DTOs is a preferred way of designing interobject communications.

Asynchronous Token

Consider an enterprise application in which a user can place purchase orders for some parts and request price quotes from various suppliers. In this case, the user may click several buttons, resulting in server-side calls to one or more destinations. On each click event of the button, a RemoteObject sends a new request to the server.

The user hits this button several times to place several orders, which in turn initiates the same number of remote calls. The user can also click different buttons, initiating calls to different destinations. Because of the asynchronous nature of remote calls in Flex, the results from each call can arrive at random times.

When each result arrives to the client, it triggers a result event, which obediently calls the result handler function written by an application programmer. So far, so good. Here’s the million-dollar question: how can the application code map arriving result objects back to the initial requesters if they can come back to the client in an arbitrary order? The fact that you place an order to purchase a Sony TV first and a DVD player 10 seconds afterward doesn’t guarantee that results will arrive to your Flex application in the same order.

The goal of the Asynchronous Token pattern is to properly route the processing on the client in response to the data arriving asynchronously from the server. Because AsyncToken is a dynamic class, you can add any properties to this class during runtime, as is done with orderNumber in Example 2-20. You can also add one or more responders that will provide the result handling. Adding responders on the token level simplifies memory management.

Example 2-20. Using the AsyncToken class


...
private function sendOrder(/*arguments go here*/):void{
var token: AsyncToken = ord.placeOrder({item:"Sony TV"});
token.orderNumber="12345";
token.responder = new Responder(processOrderPlaced, processOrderFault);
token.addResponder(new Responder(createShipment,processOrderFault));
}

AsyncToken is a local object. It is identified by a messageId that is passed with the request to the server. When the server responds, it includes a correlationId property in the message header, and Flex automatically calls the appropriate AsyncToken responders in the order they were defined. Example 2-20 calls the function send(), which starts with creating the AsyncToken instance. Then, you'll attach as many properties to this instance as you need. You may get the impression that something is not right—the values are being assigned to the instance of the token after the request has been sent to the server for execution. If so, when the result in the form of an AsyncToken comes back, it shouldn't contain values such as orderNumber and references to the responders, right? Wrong.

Flash Player executes your application’s requests in cycles driven by frame events. First, it performs the requests related to the modifications of the UI, then it gives a slice of time to process the application’s ActionScript code, and only after that does it take care of the network requests, if any. This means that all the code in the previous snippet will complete before the call ord.placeOrder({item:"Sony TV"}) is made. Always remember that from the developer’s perspective, Flex applications are single-threaded and responses are handled within each such cycle—even if the underlying communications are multithreaded.

In Example 2-20 , two responders were added to the placeOrder() request. In the case of successful order placement, two functions will be called: processOrderPlaced() and createShipment(). In the case of errors, the function processOrderFault()will be called.

You can add an instance of a Responder object to a token on the fly, as was done in the earlier code snippet, or your can provide an existing instance of a class that implements the IResponder interface—that is, that has the functions result() and fault().

To see a different way of assigning a responder, please revisit the code in Example 1-6 that demonstrates how Cairngorm’s Delegateclass adds a Command object as a responder. Sure enough, the Command object implements result() and fault() methods.

In the more traditional way of programming client/server communications, you define the handlers for results and faults:

<mx:RemoteObject id="ord" destination="Orders" result="processOrderPlaced(event)" fault="processOrderFault(event)"/>

But using AsyncToken, you can assign the handlers during runtime as was done in Example 2-20 , which gives your application additional flexibility.

At some point in time, the result will come back to the client and you can retrieve the token from the property ResultEvent.token and examine its dynamic properties (just the orderNumber in your case) that were originally added to the token:

private function processOrderPlaced(event:ResultEvent):void {
myOrderNumber:Object = event.token.orderNumber;
// if myOrderNumber is 12345, process it accordingly
}

Using the Asynchronous Token design pattern allows Flex to efficiently map associated requests and responses without the need to introduce a multithreaded environment and create some mapping tables to avoid mixing up requests and responses.

Class Factory

Flex offers you various ways to create an instance of a component. For example, in MXML, you can create an instance of MyObject and initialize its property description as follows:

<comp:MyObject id="order" description="Sony TV" />

You can achieve the same result (i.e., create an instance of MyObject and initialize the description) in ActionScript:

var order:MyObject = new MyObject(); order.description="Sony TV";

This code works fine as long as MyObject is the only possible component that can be placed in this particular screen location. But what if you need more flexibility—for example, under certain conditions you need to create either MyObject or HisObject at this location?

Instead of using the new operator, you can introduce a class with a function that will build different objects for your application based on a specified parameter. In this case, you need to implement the Class Factory design pattern—the object that will create and return either an instance of MyObject or HisObject.

You can easily find code samples of how to create class factories. Some of them are very basic, so that you just provide the name of the object you need to a factory method that has a switch statement, and it returns the proper instance of the object based on the provided name. More advanced factories are programmed to interfaces, which allows you to add new types of objects to the factory without the need to use and modify the switch each time a new object type is introduced.

A Class Factory from the Flex Framework

The Flex framework includes an implementation of the Class Factory pattern in the mx.core.ClassFactory class. Let’s quickly review its code; see Example 2-21 (we’ve removed some of the comments for brevity).

Example 2-21. mx.core.ClassFactory.as


////////////////////////////////////////////////////////////////////////////
// ADOBE SYSTEMS INCORPORATED //
// Copyright 2005-2006 Adobe Systems Incorporated //
// All Rights Reserved. //
// NOTICE: Adobe permits you to use, modify, and distribute this file //
// in accordance with the terms of the license agreement accompanying it. //
////////////////////////////////////////////////////////////////////////////

package mx.core { 

/**
 * A ClassFactory instance is a "factory object" which Flex uses
 * to generate instances of another class, each with identical properties.
 *
 * You specify a generator class when you construct the factory object.
 * Then you set the properties property on the factory object.
 * Flex uses the factory object to generate instances by calling
 * the factory object's newInstance() method.
 * 
 * The newInstance() method creates a new instance
 * of the generator class, and sets the properties specified
 * If you need to further customize the generated instances,
 * you can override the newInstance() method.
 *
 * The ClassFactory class implements the IFactory interface.
 * Therefore it lets you create objects that can be assigned to properties
 * of type IFactory, such as the itemRenderer property of a List control
 * or the itemEditor property of a DataGrid control.
 *
 * For example, suppose you write an item renderer class named ProductRenderer
 * containing a showProductImage property which can be true or false.
 * If you want to make a List control use this renderer, and have each renderer
 * instance display a product image, you would write the following code:
 *
 * var productRenderer:ClassFactory = new ClassFactory(ProductRenderer); 
 * productRenderer.properties = { showProductImage: true };
 * myList.itemRenderer = productRenderer;
 *
 * The List control calls the newInstance() method on the
 * itemRenderer to create individual instances of ProductRenderer,
 * each with showProductImage property set to true.
 * If you want a different List control to omit the product images, you use
 * the ProductRenderer class to create another ClassFactory
 * with the properties property set to { showProductImage: false }.
 *
 * Using the properties property to configure the instances
 * can be powerful, since it allows a single generator class to be used
 * in different ways.
 * However, it is very common to create non-configurable generator classes
 * which require no properties to be set.
 * For this reason, MXML lets you use the following syntax:
 *
 * <mx:List id="myList" itemRenderer="ProductRenderer"/>
 */ 
 
	 public class ClassFactory implements IFactory {
		include "../core/Version.as";
		public function ClassFactory(generator:Class = null) {
			super();
			this.generator = generator;

		}
		
		public var generator:Class;
		
		/** 
		  * An Object whose name/value pairs specify the properties to be set
		  * on each object generated by the newInstance() method.
		  *
		  * For example, if you set properties to
		  * { text: "Hello", width: 100 }, then every instance
		  * of the generator class that is generated by calling
		  * newInstance() will have its text set to
		  * "Hello" and its width set to 100.
		  */
		  
		public var properties:Object = null;

		/**
		* Creates a new instance of the generator class,
		 * with the properties specified by properties.
		 *
		 * This method implements the newInstance() method
		 * of the IFactory interface.
		 *
		 * @return The new instance that was created.
		 */
		
		public function newInstance():* {
			var instance:Object = new generator();
			if (properties != null) {
				for (var p:String in properties)	{
					instance[p] = properties[p];
				}
			}
			return instance;
		}
	} 
} 

Please read the comments for this class and pay attention to the following section:

	var productRenderer:ClassFactory = new ClassFactory(ProductRenderer);
	productRenderer.properties = { showProductImage: true };
	myList.itemRenderer = productRenderer;

The first line of this code instructs ClassFactory to create an instance of the class ProductRenderer; it's stored in the generator property of this class. The second line initializes the property showProductImage of the newly created ProductRenderer. You can initialize more than one property of the object that you create by assigning to the properties variable an object containing several key/value pairs. If you are instantiating a sealed class, make sure that the properties you are initializing exist in the class being instantiated. In the case of a dynamic object, you can initialize/create any properties on the fly.

The function newInstance() copies all properties that need to be initialized from the properties object to the corresponding properties of the newly created instance. But the earlier code example doesn't call newInstance(); is this a mistake?

No, this code is correct, and here's why. The data type of the variable itemRenderer (as well as itemEditor) of the Flex List component is IFactory, the interface that declares just one method: newInstance(). List-based components know how to instantiate objects that implement the IFactory interface, and the previous ClassFactory does implement it.

This also means that instead of providing a concrete object as an itemRenderer, you may specify a subclass of ClassFactory with the overridden method newInstance() that will be supplying the appropriate object instance.

If you’ll be using this ClassFactoryin other situations of the application code, you may need to call newInstance() explicitly.

Although mx.core.ClassFactory and item renderers are a very powerful combination when you need to customize the appearance of the data in List-based components, the ClassFactory shown in Example 2-21 has the following restrictions:

  • The Flex 3 SDK class mx.core.ClassFactory can create a factory only for a class; it can't create a factory for a class name that is being provided as a String. It can't build instances of objects based on a return of a function—a class is required.
  • Building UI objects on the fly may require applying dynamic data-driven styles. Styles are not properties, and mx.core.ClassFactory would not know what to do with them if you used them in the properties variable.
  • If you use UI components as renderers or editors, they may need to process events. It would be nice if event listeners could be attached by a class factory, and the created object would dispatch events when properties are changing. The class mx.core.ClassFactory doesn't know how to do it.
    In the Flex 4 SDK, ClassFactory allows you to dynamically assign item renderers to List-based components based on the name of the class provided in a string variable:
    <s:List itemRendererFunction="myRendererFunc"> 
     ... 
    private function myRenderedFunc (item:Object): ClassFactory {
     
    	var myRenderer:Class;

    switch (item.membershipType) { case "Trial": myRenderer=TrialMemberRenderer; break; case "Basic": myRenderer=BasicMemberRenderer; break; case "Premium": myRenderer=TrialMemberRenderer; break; } return new ClassFactory(myRenderer); }

Creating UIStaticClassFactory

This final section offers you a more advanced implementation of the Class Factory pattern that is specifically created for the UI components, especially item renderers in List-based Flex components. Please read the description of this implementation, called UIStaticClassFactory, in the code comments of Example 2-22.

Example 2-22. UIStaticClassFactory.as

////////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2009 Farata Systems LLC //
// All Rights Reserved. //
// //
// NOTICE: Farata Systems permits you to use, modify, and distribute this file //
// in accordance with the terms of the license agreement accompanying it. //
// //
////////////////////////////////////////////////////////////////////////////////////

package com.farata.core{

/**
* UIStaticClassFactory is an implementation of the Class Factory design pattern
* for dynamic creaion of UI components. It allows dynamic passing of the
* properties, styles and event listeners during the object creation.
* It's implemented as a wrapper for mx.core.ClassFactory and can
* be used as a class factory not just for classes, but for functions
* and even strings.
*
* @see mx.core.IFactory
*/

import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.core.ClassFactory;
import mx.core.IFactory;
import mx.events.FlexEvent;
import mx.styles.StyleProxy;
import mx.logging.Log;
import mx.logging.ILogger;
import mx.logging.LogEventLevel;
public class UIStaticClassFactory implements IFactory{
// A class factory object that serves as a wrapper
// for classes, functions, strings, and even class factories
private var _wrappedClassFactory : ClassFactory;
// A reference to a function if the object instances are
// to be created by a function
private var factoryFunction : Function = null;
// Styles for the UI object to be created
public var styles:Object;
// Event Listeners for the UI object to be created
public var eventListeners:Object;
private static const logger:ILogger =
Log.getLogger ("com.farata.core.UICassFactory");
public function set properties(v:Object):void {
_wrappedClassFactory.properties = v;
}
public function get properties():* {
return _wrappedClassFactory.properties ;
}
public function get wrappedClassFactory():ClassFactory {
return _wrappedClassFactory;
}

/**
* Constructor of UIClassFactory takes four arguments
* cf - The object to build. It can be a class name,
* a string containing the class name, a function,
* or another class factory object;
* props - inital values for some or all properties if the object;
* styles - styles to be applied to the object being built
* eventListeners - event listeners to be added to the object being built
*/

function UIStaticClassFactory( cf: * , props:Object = null,
styles:Object = null, eventListeners:Object = null ) {
var className:String;// if the class name was passed as a String
if ( cf is UIStaticClassFactory) {
_wrappedClassFactory =
UIStaticClassFactory(cf).wrappedClassFactory;
} if ( cf is ClassFactory) {
_wrappedClassFactory = cf;
} else if (cf is Class) {
_wrappedClassFactory = new ClassFactory(Class(cf));
} else if (cf is String) {
className = String(cf);
try {
var clazz:Class = getDefinitionByName(className) as Class;
_wrappedClassFactory = new ClassFactory(clazz);
} catch (e:Error) {
trace(" Class '"+ className + "' can't be loaded
dynamically. Ensure it's explicitly referenced in the
application file or specified via @rsl.");
}
} else if (cf is Function) {
factoryFunction = cf;
} else {
className = "null";
if (cf!=null)
className = describeType(cf).@name.toString();
trace("'" + className + "'" +
" is invalid parameter for UIClassFactory constructor.");
}
if (!_wrappedClassFactory) {
_wrappedClassFactory = new ClassFactory(Object);
}
if (props != null) _wrappedClassFactory.properties = props;
if (styles != null) this.styles = styles;
if (eventListeners != null) this.eventListeners = eventListeners;
}
/**
* The implementation of newInstance is required by IFactory
*/
public function newInstance():* {
var obj:*;
if (factoryFunction!=null){
// using a function to create an object
obj = factoryFunction();
// Copy the properties to the new object
if (properties != null) {
for (var p:String in properties) {
obj[p] = properties[p];
}
}
} else
obj = _wrappedClassFactory.newInstance();
// Set the styles on the new object
if (styles != null) {
for (var s:String in styles) {
obj.setStyle(s, styles[s]);
}
}
//add event listeners, if any
if (eventListeners != null) {
for (var e:String in eventListeners) {
obj.addEventListener(e, eventListeners[e]);
}
}
return obj;
}
}
}

Let’s examine the constructor of this class factory. It has four arguments, described in the comments. In the first argument, the code of this constructor checks the type of the object to build the factory for. In particular, if it’s a class, it just instantiates mx.core.ClassFactory.

More interestingly, if it finds that the type of the first argument is a String, it’ll load the class specified in this String and build a factory for this class, too.

One more scenario: if you’d like to specify not a class but just a function for the class factory, it can accommodate this request as well.

Example 2-23 shows you a test application that uses this class factory to dynamically build item renderers for a DataGrid not on a per-column basis but on a per-cell basis.

Example 2-23. ClassFactoryDemo.mxml


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:fx="http://www.faratasystems.com/2009/components"
layout="vertical" creationComplete="init()">
<mx:HDividedBox width="100%" height="100%">
<fx:DataGrid id="dg" dataProvider="{dp}" editable="true" height="100%"
showHeaders="false" alternatingItemColors="[#869CA7,#869CA7]"
verticalGridLines="false" variableRowHeight="true"
preventRendererReuse="columnValue">
<fx:columns>
<mx:Array>
<mx:DataGridColumn width="120" dataField="columnLabel"
headerText="Field" textAlign="right" editable="false"/>
<mx:DataGridColumn width="150" textAlign="left"
dataField="columnValue" headerText="Value"
wordWrap="true" rendererIsEditor="true"
itemRenderer="{new UIStaticClassFactory(function():* {
return switcher(dg.rendererData)})}"/>
</mx:Array>
</fx:columns>
</fx:DataGrid>
<mx:DataGrid editable="true" dataProvider="{dp}" height="100%" >
</mx:DataGrid>
</mx:HDividedBox>
<mx:Script>
<![CDATA[
import mx.controls.Label;
import mx.collections.ArrayCollection;
import mx.controls.RadioButtonGroup;
import mx.controls.TextInput;
import com.adobe.flex.extras.controls.MaskedTextInput;
import com.farata.core.UIStaticClassFactory;
[Bindable]
private var dp:ArrayCollection;
private function init() :void {
dp= new ArrayCollection ([
new ColumnRecord("First Name: ", "text", "John" ),
new ColumnRecord("Last Name: ", "text", "Smith" ),
new ColumnRecord("SSN#: ", "ssn", "123704523" ),
]);
}
private function switcher(data:Object = null) :*{
if (data == null) return new Label();
switch(data.columnType) {
case "ssn":
var mi:MaskedTextInput = new MaskedTextInput();
mi.inputMask = "###-##-####";
return mi;
}
return new TextInput();
}
]]>
</mx:Script>
</mx:Application>

The ColumnRecord in the previous example is just a little DTO (see Example 2-24).

Example 2-24. ColumnRecord.as

package
{
public class ColumnRecord
{
public var columnLabel:String;
public var columnType:String;
public var columnValue:*;
public function ColumnRecord(l:String, t:String, v:*) {
columnLabel=l;
columnType=t;
columnValue=v;
}
}
}

The ClassFactoryDemo application generates the view in Figure 2-7 , which at first sight looks like a form and a DataGrid.

But this is a container with two DataGrid objects pointing to the same data provider— a simple array that contains both the data (columnValue) and the metadata (the label, and the type of the data).

On the righthand side, it’s a regular <mx:DataGrid> from the Flex framework.

On the left is your 50-line extension of the original data grid, <fx:DataGrid>, which has a small addition—it cures the limitation of <mx:DataGrid> that reuses the same item Renderer for the entire column (its source code comes with this book).

Our goal was to create a class factory that would supply different item renderers based on some criteria:

itemRenderer="{new UIStaticClassFactory(function():* return switcher(dg.rendererData)})}"/>

The left data grid gives the closure function to UIStaticClassFactory, which calls another function, switcher(), which analyzes the metadata (the column type). If it's simple text, it just renders it as a Label, but if the type of the column is ssn, it renders it as a MaskedTextInput.

Please note that this class factory does not know in advance what to build, as you don’t use static linkage here.

This example kills two birds with one stone. First, it shows a more advanced class factory, and second, it illustrates how you can build dynamic forms having a DataGrid with dynamic data renderers under the hood.

In general, using components for item renderers and editors may be challenging. When you use a renderer as an editor, you have at your disposal powerful control with a built-in mask. In the earlier view, if a user decides to change the value of SSN#, he will be restricted by the mask MaskedTextInput.

Even though having many different item renderers may be a bit expensive from the performance view, it brings you a lot of flexibility and a nicer-looking UI.

The authors of this book use item renderers as item editors and have a single point of customization for controls.

Using class factories allows you to make grids that do not look like grids but rather like dynamic forms. They can support runtime properties, styles, and other types of plug-ins either via MXML or—even better—via well-structured ActionScript.

OK, this can’t all be that rosy, and there is a little issue—you can’t declare properties needed for these custom renderer components on the DataGridColumn tag. When you write in MXML something like itemRenderer="MyClassFactory", there is no room for you to specify properties of the renderer component. You have to use the <mx:Component> tag in order to “embed” them into a class.

Creating UIClassFactory

Using the class UIStaticClassFactory with item renderers is a good idea, but let’s have a little more fun with factories. This new demo application uses another version of class factory first. The source code of the more advanced UIClassFactory will follow.

This version of the factory shows you how you can create dynamic styles, properties, and events in a declarative way. The demo application looks like Example 2-25 .

Example 2-25. ClassFactoryDemo2.mxml

fx:generator>
<fx:properties>
<mx:Object inputMask = "###-###-####" />
</fx:properties>
</fx:UIClassFactory>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn dataField="STATUS" headerText="Status"
rendererIsEditor="true" />
<mx:DataGridColumn dataField="SS_NUMBER" rendererIsEditor="true"
headerText="SSN#" >
<mx:itemRenderer>
<fx:UIClassFactory>
<fx:generator>
{MaskedTextInput}
</fx:generator>
<fx:properties>
<mx:Object inputMask = "###-##-####" />
</fx:properties>
</fx:UIClassFactory>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn dataField="SALARY" editable="false" headerText="Salary"
textAlign="right" rendererIsEditor="true">
<mx:itemRenderer>
<fx:UIClassFactory>
<fx:generator>
{TextInput}
</fx:generator>
<fx:runtimeStyles>
<mx:Object
fontWeight="{function(d:*):String { return
d.SALARY>50000?'normal':'bold'}}"
backgroundColor="{function(d:*):String { return
d.SALARY>30000?'green':'red'}}"/>
</fx:runtimeStyles>
</fx:UIClassFactory>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn dataField="START_DATE" headerText="Start Date"
itemRenderer="mx.controls.DateField" editorDataField="selectedDate"
rendererIsEditor="true" />
<mx:DataGridColumn dataField="BENE_HEALTH_INS" editable="false"
headerText="Health" >
<mx:itemRenderer>
<fx:UIClassFactory>
<fx:generator>
{CheckBox}
</fx:generator>
<fx:runtimeProperties>
<mx:Object
selected="{function(d:*):Boolean { return
d.BENE_HEALTH_INS=='Y'}}"/>
</fx:runtimeProperties>
<fx:eventListeners>
<mx:Object
click="{function (e:MouseEvent): void {
trace('hello:'+e);
beneHealthClick(e);
}
}"/>
</fx:eventListeners>
</fx:UIClassFactory>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn dataField="SEX" editable="false" headerText="Sex" />
</mx:columns>
</mx:DataGrid>
<mx:Script>
<![CDATA[
import mx.controls.Label;
import mx.collections.ArrayCollection;
import mx.controls.RadioButtonGroup;
import mx.controls.TextInput;
import com.farata.core.UIClassFactory;
import com.adobe.flex.extras.controls.MaskedTextInput;
import mx.controls.CheckBox;
private function init() :void {
var dp:Array = [
{EMP_ID:1,MANAGER_ID:200,EMP_FNAME:"John",
EMP_LNAME:"Smith",DEPT_ID:100,STREET:"10 Baker Str",
CITY:"New York",STATE:"NY",SALARY:25000,
ZIP_CODE:"10001",PHONE:"2125551111",STATUS:"A",
SS_NUMBER:"123456789", START_DATE:new Date("10/1/1998"),
BENE_HEALTH_INS:"Y",SEX:"M"},
{EMP_ID:2,MANAGER_ID:200,EMP_FNAME:"Jane",
EMP_LNAME:"Smith",DEPT_ID:100,STREET:"10 Baker Str",
CITY:"New York",STATE:"NY",SALARY:75000,
ZIP_CODE:"10001",PHONE:"2121115555",STATUS:"A",
SS_NUMBER:"987654321",START_DATE:new Date("10/1/1997"),
BENE_HEALTH_INS:"N",SEX:"F"},
{EMP_ID:3,MANAGER_ID:200,EMP_FNAME:"Count",
EMP_LNAME:"Dracula",DEPT_ID:100,STREET:"10 Baker Str",
CITY:"New York",STATE:"NY",SALARY:175000,
ZIP_CODE:"10001",PHONE:"2121117777",STATUS:"A",
SS_NUMBER:"321654321",START_DATE:new Date("10/1/1908"),
BENE_HEALTH_INS:"Y",SEX:"F"}
];
dg.dataProvider = dp;
}
private function beneHealthClick(e : MouseEvent ) : void {
e.currentTarget.data.BENE_HEALT_INS = e.currentTarget.selected?"Y":"N";
}
]]>
</mx:Script>
</mx:Application>

If you run this application, you’ll see the window shown in Figure 2-8 with item renderers assigning dynamic properties, styles, and event listeners (as this book is printed in black, keep in mind that the actual background color of the salary in the first row is red, and in the other two is green):

Here’s how simple and sweet it is:

<mx:itemRenderer>
<fx:UIClassFactory>
<fx:generator>

{MaskedTextInput}
</fx:generator>
<fx:properties>

<mx:Object inputMask = "###-###-####" />
</fx:properties>
</fx:UIClassFactory> 
</mx:itemRenderer> 

We declare that this item renderer will use the class factory that should build an instance of MaskedTextInput, and the inputMask property of this class to be generated is “######-####”.

Now you can assign values to the properties of the instances-to-be of a class factory!

The next code snippet shows you how to dynamically change the fontWeightstyles and background column depending on the value of the Salary in each row:

<fx:runtimeStyles> 
<mx:Object fontWeight="{function(d:*):String { return d.SALARY>50000?'normal':'bold'}}" backgroundColor="{function(d:*):String { return d.SALARY>30000?'green':'red'}}"/> </fx:runtimeStyles>

The next code fragment renders the health insurance data as CheckBox, sets its selectedproperty based on the data value (Y or N), and adds an event listener to process clicked events of this CheckBox:


<mx:itemRenderer>
<fx:UIClassFactory>
<fx:generator>
{CheckBox}
</fx:generator>
<fx:runtimeProperties>
<mx:Object
selected="{function(d:*):Boolean { return
d.BENE_HEALTH_INS=='Y'}}"/>
</fx:runtimeProperties>
<fx:eventListeners>
<mx:Object
click="{function (e:MouseEvent): void {
trace('hello:'+e);
beneHealthClick(e);
}
}"/>
</fx:eventListeners>
</fx:UIClassFactory>
</mx:itemRenderer>

We hope you’ve enjoyed this sample application. To examine the source code of the all-new UIClassFactory, see Example 2-26 .

Example 2-26. UIClassFactory.as


////////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2009 Farata Systems LLC //
// All Rights Reserved. //
// //
// NOTICE: Farata Systems permits you to use, modify, and distribute this file //
// in accordance with the terms of the license agreement accompanying it. //
// //
////////////////////////////////////////////////////////////////////////////////////
package com.farata.core{
/**
* UIClassFactory is an implementation of the Class Factory design pattern
* for dynamic creaion of UI components. It allows dynamic passing of the
* propeties, styles and event listeners during the object creation.
* It's implemented as a wrapper for mx.core.ClassFactory and can
* be used as a class factory not just for classes, but for functions
* and even strings.
*
* @see mx.core.IFactory
*/
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import mx.controls.Label;
import mx.core.ClassFactory;
import mx.core.IFactory;
import mx.events.FlexEvent;
import mx.logging.ILogger;
import mx.logging.Log;
public class UIClassFactory implements IFactory{
// A class factory object that serves as a wrapper
// for classes, functions, strings, and even class factories
private var _wrappedClassFactory : ClassFactory;
// A reference to a function if the object instances are
// to be created by a function
private var factoryFunction : Function = null;
// Styles for the UI object to be created
public var styles:Object;
// Runtime Styles for the UI object to be created
public var runtimeStyles:Object;
// Runtime Properties for the UI object to be created
public var runtimeProperties:Object;
// Event Listeners for the UI object to be created
public var eventListeners:Object;
private static const logger:ILogger =
Log.getLogger ("com.farata.core.UICassFactory");
public var properties:Object = {};
public function get wrappedClassFactory():ClassFactory {
return _wrappedClassFactory;
}
public function set generator (cf:Object) : void {
var className:String;// if the class name was passed as a String
if (cf == null)
cf = Label;
if ( cf is UIClassFactory) {
_wrappedClassFactory = UIClassFactory(cf).wrappedClassFactory;
} if ( cf is ClassFactory) {
_wrappedClassFactory = cf as ClassFactory;
} else if (cf is Class) {
_wrappedClassFactory = new ClassFactory(Class(cf));
} else if (cf is String) {
className = String(cf);
try {
var clazz:Class = getDefinitionByName(className) as Class;
_wrappedClassFactory = new ClassFactory(clazz);
} catch (e:Error) {
trace(" Class '"+ className + "' can't be loaded
dynamically. Ensure it's explicitly referenced
in the application file or specified via @rsl.");
}
} else if (cf is Function) {
factoryFunction = cf as Function;
} else {
className = "null";
if (cf!=null)
className = describeType(cf).@name.toString();
trace("'" + className + "'" + " is invalid parameter for
UIClassFactory constructor.");
}
if (!_wrappedClassFactory) {
_wrappedClassFactory = new ClassFactory(Object);
}
}
/**
* Constructor of UIClassFactory takes four arguments
* cf - The object to build. It can be a class name,
* a string containing the class name, a function,
* or another class factory object;
* props - inital values for some or all properties if the object;
* styles - styles to be applied to the object being built
* eventListeners - event listeners to be added to the object being built
*/
public function UIClassFactory( cf: Object = null , props:Object = null,
styles:Object = null, eventListeners:Object = null ) {
generator = cf;
if (props != null) this.properties = props;
if (styles != null) this.styles = styles;
if (eventListeners != null) this.eventListeners = eventListeners;
}
/**
* The implementation of newInstance is required by IFactory
*/
public function newInstance():* {
var obj:*;
if (factoryFunction!=null){
// using a function to create an object
obj = factoryFunction();
} else
obj = _wrappedClassFactory.newInstance();
// Copy(aggregate) the properties to the new object
if (properties != null) {
for (var p:String in properties) {
obj[p] = properties[p];
}
}
// Set the styles on the new object
if (styles != null) {
for (var s:String in styles) {
obj.setStyle(s, styles[s]);
}
}
// add event listeners, if any
if (eventListeners != null) {
for (var e:String in eventListeners) {
obj.addEventListener(e, eventListeners[e]);
}
}
// Watch data modifications
obj.addEventListener(FlexEvent.DATA_CHANGE, onDataChange);
return obj;
}
/**
* onDataChange is the handler for the DATA_CHANGE events. It uses
* runtimeStyles and runtimeProperties, which were added to Clear Toolkit's
* version of the DataGridColumn to handle styles and properties that were
* added dynamically.
*
* If you'll use this UIClassFactory with regular DataGridColumns that does
* not support dynamic styles, the onDataChange function won't find any
* runtimeStyles or runtimeProperties and won't do anything.
*/
private function onDataChange(event:FlexEvent):void{
// Skip this call if caused by header renderers
var renderer:Object = event.currentTarget;
var functionObject:Function;
var value:*;
// Act only on 'dynamic style' columns
for (var style:String in runtimeStyles) {
functionObject = null;
value = runtimeStyles[style];
if (value is Function){
functionObject = value as Function;
}
if (null != functionObject) {
try {
value =
functionObject(renderer.data) ;
renderer.setStyle(style, value);
} catch (e:Error) {
logger.error(e.message);
}
} else
renderer.setStyle(style, value);
}
for (var prop:String in runtimeProperties) {
functionObject = null;
value = runtimeProperties[prop];
if ( value is Function ){
functionObject = value as Function;
}
if (null != functionObject ) {
try {
value =functionObject(renderer.data) ;
renderer[prop] = value;
} catch (e:Error) {
logger.error(e.message);
}
} else
renderer[prop] = value;
}
}
}
}

If you compare the code of the UIStaticClassFactory with the code of UIClassFactory, you'll notice that the latter introduces the property generator—an object to be created by the factory.

The function onDataChange() is a handler for the DATA_Change events. However, this function is relevant only if you are going to use UIClassFactory with the DataGrid from the Clear Toolkit's component library.

This concludes a brief overview of selected design patterns and shows how they can make your Flex programming more efficient. This chapter covered selected design patterns used in Flex applications. In many cases, Flex gives you a hand, allowing you to use a particular design pattern based on some of the existing elements of the Flex framework. For example, instead of creating a new singleton class and finding references to it with a number of getInstance() function calls, you can reuse the readily available singleton application, available in the Flex framework. The proxy pattern used in this chapter is based on ObjectProxy, which is also a part of the Flex SDK.

A creative approach to class factories can make your application a lot more flexible. In Chapter 4 , you’ll see how you can use factories to integrate BlazeDS and the Spring framework.

Design patterns is a lingua franca, understood by all software developers in general and Flex developers in particular. By the end of this book, you will be more comfortable speaking this language, too.

Enterprise Development with Flex book cover

This excerpt is from Enterprise Development with Flex. If you want to use Adobe Flex to build production-quality Rich Internet Applications for the enterprise, this groundbreaking book shows you exactly what's required. You'll learn efficient techniques and best practices, and compare several frameworks and tools available for RIA development -- well beyond anything you'll find in Flex tutorials and product documentation. Through many practical examples, the authors impart their considerable experience to help you overcome challenges during your project's life cycle.

buy button