On a pleasant day, I thought of evaluating the various frameworks available for flex. I encountered with variety of them like Cairngorm, PureMVC, RobotLegs etc. Thinking of evaluating each of them , I started my work with RobotLegs. This article describes my experience with RobotLegs as a flex framework.

What is RobotLegs?

Robotlegs is a pure AS3 micro-architecture (framework) with a light footprint and limited scope. Simply put, Robotlegs is there to help you wire your objects together. The framework promotes loose coupling and avoiding the use of Singletons and statics which help you write code that is highly testable.

The framework supplies a default implementation based on the Model-View-Controller meta-design pattern. It revolves around the Dependency Injection design pattern.

The class diagram for a typical robot legs application would look like as:


RobotLegs Architecture

 

One will typically have following parts in the application using robotlegs: View, Model, Mediators, Command, Service, Actor, Context and Events. Each of these parts can be briefly described as follows:

 

Context:

At the heart of any RobotLegs implementation lies the Context. The Context, or Contexts as the case may be, provides the mechanism by which any given implementation’s tiers will communicate. The Context has three functions within an application: provide initialization, provide de-initialization, and provide the central event bus for communication

The context class extends from org.robotlegs.mvcs.Context and in a general case override startup() method.

A typical implementation of startup method would look like:

 

override public function startup():void
{
	commandMap.mapEvent(ContextEvent.STARTUP, StartUpCommand, ContextEvent, true);

	// MAP OTHER EVENTS
	// E.G.
	// commandMap.mapEvent(ApplicationEvents.LOGIN, LoginCommand, ApplicationEvents);

	// INJECT MODEL (USUALLY SINGLETON)
	// E.G. injector.mapSingleton( ApplicationModel );

	// INJECT SERVICE
	// injector.mapSingletonOf( IFacebookService, FacebookService);

	// MAP VIEW-MEDIATORS
	// E.G. mediatorMap.mapView(LoginView, LoginViewMediator);

	// DISPATCH START UP EVENT
	// dispatchEvent(new ContextEvent(ContextEvent.STARTUP));
}

 

The StartUpCommand is responsible for handling the application creation complete. In execute method of the StartUpCommand you will need to say that the start up is complete. This is done by dispatching ContextEvent.STARTUP_COMPLETE from the execute()method of StartUpCommand.

 

View:

A view is typically the user interface part of your application. The view manages the display of information.

 

Mediator:

The Mediator class represents view tire. Classes that extend Mediator are used to handle framework interaction with View Components. A Mediator will listen for framework events, add event listeners to the View Components, and send framework events in response to events received from the View Components they are responsible for. This allows the developer to put application specific logic on the Mediator, and avoid coupling View components to specific applications.

A mediator class will look like this:

public class MyMediator extends Mediator implements IMediator 
{ 
	[Inject] 
	public var myCustomComponent:MyCustomComponent;
	// NOTE:
	// you can also inject service and model in the mediator 

	override public function onRegister():void 
	{ 
		//adding an event listener to the Context for framework events 
		eventMap.mapListener( eventDispatcher, MyCustomEvent.DO_STUFF, handleDoStuff );
		
		//adding an event listener to the view component being mediated 
		eventMap.mapListener( myCustomComponent, MyCustomEvent.DID_SOME_STUFF, handleDidSomeStuff) 
	}

	protected function handleDoStuff(event:MyCustomEvent):void 
	{
	}

	protected function handleDidSomeStuff():void 
	{
	}
} 

 

Controller & Command:

The Controller tier is represented by the Command class. Commands are stateless, short-lived objects used to perform a single unit of work within an application. Commands are appropriate for communication between application tiers and are able to send system events that will either launch other Commands or be received by a Mediator to perform work on a View Component in response to the event. Commands are an excellent place to encapsulate the business logic of your application.

A typical command class looks like this:

public class MyCommand extends Command 
{
	[Inject] 
	public var event:MyCustomEvent; 

	[Inject] public var model:MyModel; 

	override public function execute():void 
	{ 
		model.updateData( event.myCustomEventPayload ); 
	}
} 

 

Model, Service And Actors:

Conceptually there are many similarities between the service and model tiers in the MVCS architecture. Because of this similarity, models and services are extended from the same base Actor class. A class that extends the Actor base can serve many functions within your application architecture. Within the context of MVCS, we are going to utilize extensions of Actor for defining both the models and the services an application will need to manage data and communicate with external entities.

 

Model:

Model classes for use in the model tier encapsulate and provide an API for data. Models send event notifications when work has been performed on the data model. Models are generally highly portable entities.

Service:

A Service for use in the service tier communicates with “the outside world” from within an application. Web services, file access, or any action that takes place outside of the scope of your application is appropriate for a service class. Service classes dispatch system events in response to external events. A service should be highly portable, encapsulating interaction with an external service.

 

Events:

Robotlegs uses native flash events for communication between framework actors. Custom events are typically utilized for this purpose, it is however possible to use existing Flash events for this same purpose. Robotlegs does not support Event bubbling, as it does not depend on the Flash display list as an event bus. Utilizing custom events allows developers to add properties to the Event that can be used as strongly typed payloads for system events between framework actors.

Events are sent from all framework actors: Mediators, Services, Models, and Commands. Mediators are the only actors that receive framework events. Commands are triggered in response to framework events. An event can be both received by a Mediator as well as trigger a command.

Model and service classes should not listen for or respond to events. Doing so would tightly couple them to application specific logic and reduce the potential for portability and reuse.

Overall work flow for the framework:

The work flow for a robot legs application looks as follows:

  1. A instance of context is created by the flex application..
  2. The context maps mediator-view, event-commands
  3. In mediators, we map the events, handler functions for those and the dispatcher of that event. Th event can come from the view or some other component of the framework.
  4. The user interaction that happens, for e.g. a button click, those events are directly listened by mediators or the view dispatches a event which would be listened by the mediator.
  5. The mediator on receiving that event acts dispatching a new event which would be mapped to a corresponding command. The command manipulates the model or invokes the service.
  6. If the command manipulates the model, then the model dispatches a new custom event for model update. This event is again listened by a mediator which in turn updates the view accordingly.
  7. If a external service is invoked, the result handler for the service updates the model or dispatches a new event which in turn is listened by the mediator.

 

One can deviate from the above work flow in case there are lot of service calls or lot of model update. We can directly inject the Model or Service in our mediator in our mediator and invoke there functions. By doing this, we can eliminate the need for multiple commands corresponding events.

References:

Following are the links which might be helpful while working with robotlegs:

  1. http://www.robotlegs.org
  2. http://www.robotlegs.org/examples/
  3. https://github.com/robotlegs/robotlegs-framework/wiki/Best-Practices
  4. http://api.robotlegs.org/
  5. Source code: https://github.com/robotlegs/robotlegs-framework