Anonymous MVC Framework III (Controller)

October 26

The primary focal point for aMVC is the anaonymous controller. this class is in fact the motivator for the creation of the aMVC architecture. The basic underlying motivation was a centralized point of control for messaging that was not dependent on global constants, or a priori knowledge of events or functional commands.
This is one of the major drawbacks of architectures like Cairngorm (other than class overload). In Cairngorm, the FrontController class is a central mechanism in  the application that links events to responders (Commands). In a shared production environment, this requires an integration step in development work to capture all communication in a central place. In the original formulation there was also a conflict introduced by using Modular development, where there was conflict between the central application controller, and those built to support Module functionality. This conflict was resolved, thanks to work by groups such as Universal Mind, by allowing the application controller to register the FrontControllers of individual modules

In the aMVC formulation, the Controller class acts as a message gateway. Events, defined as constants elsewhere in application, are registered with the controller anonymously via the use of a Dictionary. As part of this registration (via the EventRegistrationDTO), a responder is passed and assigned via the Dictionary to this event. This initial registration and that of other interested parties are captured in the same Dictionary entry. When an event of this type is dispatched, all interested parties are notified of the event via the registered responder.

The controller neither knows nor cares who is doing the registration, who dispatched the event (is is dispatched directly on the controller, which is a Singleton), or who will handle (or initiate) actions that correspond to this event.  As outlined in the function relationship diagram, a typical flow would have a Command instance registering interest with the Controller for an event that is dispatched by a view component that responds to user interaction. This is not the only scenario e.g. view registers response handler from an event dispatch elsewhere in the application.

The framework relies on a single event Class the DataTransportEvent that can be utilized to pass any data or none. These classes are outlined here:

Controller.as

/*
 * Controller.as
 *
 * Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
 *                        www.dkohles.com
 *
 * Date: April 10, 2010
 * Author: darin@dkohles.com
 *
 */
package com.dkohles.core.control
{
import com.dkohles.core.base.SingletonBase;
import com.dkohles.core.events.DataTransportEvent;
import com.dkohles.core.events.EventRegistrationDTO;

import flash.utils.Dictionary;

import mx.rpc.IResponder;

public class Controller extends SingletonBase
{
private var responseDirectory:Dictionary;
private var eventDirectory:Dictionary;

protected var svc:M3RemoteServices;
protected var model:M3Model;

public function M3Controller()
{
super();
}

/**
* Add a responder to an event type. Used by module classes to register interest in
* external events.
* @param reg pass through object containing event type information and the responder for the event.
*
*/
public function registerHandler( reg:EventRegistrationDTO ):void
{
if( eventDirectory == null ){
eventDirectory = new Dictionary();
}

if( eventDirectory[ reg.eventName ] == null ){
eventDirectory[ reg.eventName ] = true;
addEventListener( reg.eventName, handleEvent );
}

if( responseDirectory == null ){
responseDirectory = new Dictionary();
}

if( responseDirectory[ reg.eventName ] == null ){
responseDirectory[ reg.eventName ] = new Array();
}

( responseDirectory[ reg.eventName ] as Array).push( reg.responder );
}

/**
* Remove notification interest by responder. Used to decouple component from external
* events that had been previously been tracked. Also clean up the controller dictionary
* if no other parties are interested.
*
* @param reg pass through object containing event type information and the responder for the event.
*
*/
public function deRegisterHandler( reg:EventRegistrationDTO ):void
{
var index:int = (responseDirectory[ reg.eventName ] as Array).indexOf( reg.responder );
if(index >=0 ) (responseDirectory[ reg.eventName ] as Array).splice( index, 1 );

if( (responseDirectory[ reg.eventName ] as Array).length == 0)
{
responseDirectory[ reg.eventName ] = null;
this.removeEventListener( reg.eventName, handleEvent );
}
}

/**
* Pass the event directly to the responder(s) directly.
*
* @param evt event fired by normal application flow or user gesture
*
*/
private function handleEvent( evt:DataTransportEvent ):void
{
var respArray:Array = responseDirectory[ evt.type ];
if( respArray != null && respArray.length > 0 ){
for(var i:int = 0 ; i < respArray.length ; i++ ){
if( (respArray[i] as IResponder).result != null ){
(respArray[i] as IResponder).result( evt.data );
}
}
}
}

/**
* Retrieve responders for a given event.
*
* @param evt event type of interest.
*
*/
private function getResponders( type:String ):Array
{
var respArray:Array;
if( eventDirectory[ type ] ){
respArray = responseDirectory[ type ];
}
}
}
}

EventRegistrationDTO.as

/*
* EventRegistrationDTO.as
*
* Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
*                        www.dkohles.com
 *
* Date: April 10, 2010
* Author: darin@dkohles.com
*
*/
package com.dkohles.core.events
{
import mx.rpc.IResponder;
import mx.rpc.Responder;

public class EventRegistrationDTO
{
public var responder:Responder;
public var eventName:String;

public function EventRegistrationDTO( evt:String, resp:Responder )
{
this.eventName = evt;
this.responder = resp;
}

}
}

DataTransportEvent.as

/*
* DataTransportEvent.as
*
* Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
*                        www.dkohles.com
 *
* Date: April 10, 2010
* Author: darin@dkohles.com
*
*/
package com.dkohles.core.events
{
import flash.events.Event;

public class DataTransportEvent extends Event
{
public var data:*;

public function DataTransportEvent(type:String, data:*, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);

this.data = data;
}

}
}

Advertisement

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 )

Connecting to %s

Follow

Get every new post delivered to your Inbox.