Getting Started with Cairngorm – Part 5

In Part 4 you saw the full Service to Worker pattern demonstrated. However, the method discussed in the last tutorial doesn’t fit every situation. In this tutorial you will learn a few “best-practices” for Cairngorm projects as well as an extension to the Service to Worker pattern for more complex cases.

Delegates, Commands, and Responders

These classes (Delegates, Commands, and Responders) have specific responsibilities. Many developers run into problems when they do not adhere to these responsibilities. The following tips are guidelines for your code.

  • Responders – Responders should deal only in strongly-typed application objects. Responders may set values on the model.
  • Commands – Commands never deal directly with server interaction. Commands may set values on the model.
  • Delegates – Delegates should pass strongly typed strongly-typed application objects to the Responder. If the Delegate doesn’t receive strongly-typed application objects, it must parse and convert the data into that format.

Cairngorm Delegate Data Diagram

Figure 1 – Data Transmission in the Service to Worker Pattern

The goal of this separation of responsibility is that services should be able to be switched out with only a change in the delegate. This may sound a bit unimportant, but if you are working for a large company, the server-side implementation can change drastically from development to production. For this to work properly, the service call will need to have two responders: the Delegate, and the actual Responder. Figure 1 illustrates this separation. The data passed from the service to the delegate can be in virtually any format, but the transfer from the Delegate to the Responder needs to only be application data (VO’s, model classes).

In this case, the Delegate now has an added responsibility, parsing the raw data. To accomplish this, you can create a factory class to parse the data. In the sample below the class DeliciousFactory (because it parses data from a Del.icio.us feed) has a method buildPostArrayFromJSON which handles this responsibility.

Actionscript:

...
package net.davidtucker.deliciousbrowser.business {
import com.adobe.cairngorm.business.ServiceLocator;
import mx.rpc.AsyncToken;
import mx.rpc.IResponder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import net.davidtucker.deliciousbrowser.factories.DeliciousFactory;
public class PostsDelegate {
private var responder:IResponder;
private var service:Object;
public function PostsDelegate( responder:IResponder ) {
this.responder = responder;
this.service = ServiceLocator.getInstance().getHTTPService( "sampleService" );
}
public function getRecentPosts():void {
// Call the Service and Attach that call to an AsyncToken
var token:AsyncToken = service.send(params);
// Create a Responder for the call
var responder:mx.rpc.Responder = new mx.rpc.Responder(onResult, onFault);
// Add the Responder to the AsyncToken
token.addResponder(responder);
}
private function onResult( e:ResultEvent ):void {
// Parse JSON into Array of VO's
var posts:Array = DeliciousFactory.buildPostArrayFromJSON( e.result as String );
// Pass VO Array to Responder
responder.result( new ResultEvent( ResultEvent.RESULT, false, true, posts ) );
}
private function onFault( e:FaultEvent ):void {
}
}
}...

Code Example 1 – A Delegate Parsing Raw Server Data

Parsing the server data is only a part of this extended design pattern. For this to work properly with the traditional Cairngorm flow, the delegate must “intercept” the result of the service call. To accomplish this, you will attach an AsyncToken [Reference] to the service call, create a responder for the call, and then attach the responder to the AsyncToken. This is illustrated in lines 23-30 of Code Example 1.

Now that the delegate has “intercepted” the result of the service call, it need to have methods to parse the data. When you created the responder inside of the delegate (line 27 of Code Example 1), you passed in a result and fault method. In this case it was onResult and onFault. You now need to add these methods to the delegate.

To pass the parsed data to the original responder, you will need to create a new instance of the ResultEvent [Reference] with the parsed data in the result property (line 40 of Code Example 1). This event will be passed as an argument to the original responder’s result method.

Setting ModelLocator Values

Within a Cairngorm application, it can be extremely tempting to set values of ModelLocator variables in your events, delegates, or views, but this should be avoided. These values should be set only in the Command Level (see Figure 1) of the application. This means that you can set these values in a Command or Responder. This keeps every class in tune with its true function.

Sequence Commands

Cairngorm also contains a class, SequenceCommand [Reference] that allows the developer to chain command/events together for sequential execution. Initially this may seems like it breaks the framework’s rule oft having every command triggered by an event, but it doesn’t. Inside of a SequenceCommand you define the nextEvent property (which is an instance of a CairngormEvent). This event is executed when the executeNextCommand method is called. This is the most effective way to attach multiple commands to a single user gesture.

Actionscript:
public class SampleSequenceCommand extends SequenceCommand implements ICommand, IResponder {
public function SampleSequenceCommand() {
this.nextEvent = new GetPostsEvent();
}
override public function execute( e:CairngormEvent ):void {
}
public function result( event:Object ):void {
this.executeNextCommand();
}
public function fault( event:Object):void {
}
}

NOTE: The SequenceCommand class assumes that you are not separating your Command and Responder. You could easily extend the architecture and create a SequenceResponder class to achieve the same effect.

ViewHelper and ViewLocator Classes

Many people have inquired about the ViewHelper [Reference] and ViewLocator [Reference] classes. Both of these classes are now deprecated as of Cairngorm 2.1, and it is considered bad practice to use either of these classes in a new Cairngorm project. Should you be working with an existing project that still uses these classes, I would recommend refactoring your code to meet Cairngorm 2.2 standards.

Summary of Tips

  1. Don’t use ViewHelpers and ViewLocators
  2. Only set ModelLocator variables in the Command Level (Command or Responder).
  3. SequenceCommand can be used to chain multiple commands to a single user gesture.
  4. Delegates deal in raw service data (which could be application data), but Responders only deal in strongly-typed application data.
  5. Commands do not directly communicate with services.

Application Code
Beginning Code Download (9 Kb)
Finished Code Download (12 Kb)

References
AS3CoreLib

Looking Ahead

In the next (and final) tutorial on Cairngorm, you will learn tips to make your Cairngorm development go faster as well as learning more “best practices” for Cairngorm development.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s