Email Updates RSS Subscribe
Line

This blog is created and maintained by the technical team at Hook in an effort to preserve and share the insights and experience gained during the research and testing phases of our development process. Often, much of this information is lost or hidden once a project is completed. These articles aim to revisit, expand and/or review the concepts that seem worth exploring further. The site also serves as a platform for releasing tools developed internally to help streamline ad development.

Launch
Line

Hook is a digital production company that develops interactive content for industry leading agencies and their brands. For more information visit www.byhook.com.

Line

StopWatch – A Simple MicroMVC Example

Line
Posted on November 29th, 2010 by Chris
Line

This post is an example project that shows the basics of setting up a project using Hook’s MicroMVC system. This project shows you how to use the various components of MicroMVC and features like the event bubbling. There are a lot of different ways to set up a project so this post is intended as a guide to get you started.

The project is set up with a model centric focus; meaning the views are updated in response to changes in the data model and views don’t manage their own states. In this type of set up interaction takes the following path.

  1. User action of some type (button click, etc) causes a view to dispatch an event that is observed by that view’s mediator.
  2. The mediator dispatches an appropriate event to the context event dispatcher.
  3. The mediator’s event is observed by a pre-registered command and an instance of the appropriate command class is created and executed.
  4. The command updates data in the relevant model.
  5. The model dispatches an event in response to the change in its data. This event carries any relevant data values with it.
  6. A mediator observes the event from the model and updates its view component.

Bootstrapping Process and Classes

These classes are used to get the basic application set up in your FLA. Our bootstrap process consists of several steps since we need to work around some issues in AS2. Make sure you review the classes and the project FLA.

  1. Instantiate a context
  2. Map our view and command bootstrap commands to ContextEvent.STARTUP_COMPLETE
  3. Map our model bootstrap to UIEvent.READY
  4. The view tier is created and when it is ready it dispatches UIEvent.READY
  5. The context observes UIEvent.READY and executes our model bootstrap command
  6. When our model is registered it dispatches StopWatchModelEvent.REGISTER which is observed by StopWatchViewMediator which makes the views available

Façade.as

Façade provides a point of entry for your MicroMVC application within your FLA. Façade is basically a wrapper for your context, it is useful to wrap it in case you want to have it as a singleton or need to do some other work before you start your MVC instance.

Here is our Façade:

class Facade extends MovieClip
{
	private var _context:ExtendContext
 
 
 
	public function Facade(externalView:MovieClip) 
	{
 
 
		_context = new ExtendContext (externalView,false)
 
 
 
 
		_context.startup()
	}
 
 
}

Here is how we add our Façade to the _root timeline.

 
var f:Facade = new Facade (this)

ExtendContext.as

ExtendContext is how we set up the MicroMVC application. It extends Context.as to map 3 commands at startup, then call super.startup() which dispatches the ContextEvent.STARTUP_COMPLETE event. The 3 commands mapped at startup correspond to the 3 areas of a MVC application that must be established. I like setting up as much as I can in this style since it keeps your context clean and gives you 3 distinct areas to set up the parts of the application. You can also easily change the execution order this way. Notice that all 3 of these command maps have their oneShot property set to true since we only need to call them once, then the maps can be disposed.

 
class ExtendContext extends Context
{
	private static var _stringDescription:String = "ExtendContext"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}	
	public function ExtendContext(externalView:MovieClip, autoStartup:Boolean) 
	{
		super(externalView, autoStartup);
 
	}
 
	public function startup () {
 
		_commandMap.mapEvent (ContextEvent.STARTUP_COMPLETE,SetUpViewCommand.stringDescription,true)
 
		_commandMap.mapEvent (ContextEvent.STARTUP_COMPLETE,SetUpControlCommand.stringDescription,true)
 
		_commandMap.mapEvent (UIEvent.READY, SetUpModelCommand.stringDescription, true);
 
 
 
 
		super.startup()
 
	}
 
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy()
	}
 
	public function getStringDescription():String 
	{
		return ExtendContext.stringDescription
	}
 
}

Setting Up the View Tier

When possible I prefer to set the view tier first so that it is ready when the model tier becomes available. I think it is best to start either with the view or model tier depending on your needs. In order to illustrate how the view tier functions I will detail it from the bottom up; starting with the views, then their mediators, then showing how that relationship is mapped. In this type of development views don’t really need to know much about their children typically since each major view element is associated with a mediator. You can choose how many of how few mediators to use and how complex to make the views.

StopWatchView.as

This is the highest level view we will construct within our application. This view gets attached to the _contextView that our application will create when it is bootstrapped. I prefer to create a top level view that will be a child of the _contextView, rather than extend the ContextView class.

All we really need this class to do is inform us when the model tier is set up and ready for use. In order to do this we create a method ready() that is called from frame 2 of the view and dispatches a UIEvent.READY that will be heard by this view’s mediator.

IMPORTANT NOTE ON CODE EXECUTION IN AS2

In AS3 code execution is bottom-up, meaning if you have a view hierarchy the pieces deepest in the hierarchy are created first and the pieces at the top are created also. In AS2 it is the exact opposite, a top-down execution. The top view is created then the next level down is created. Since we want to know when our views have been created and their mediators registered, BEFORE we do anything else we have to give the views 1 frame to dispatch their events and get their mediators before we know they are ready. So we add this call to ready() in frame 2 of StopWatchView.as. If you have data coming in from some external services or loader that is happening you might not need to do this, but using this method allows you to ensure that the views are ready. Since we are using event bubbling to know when to attach our mediators we need to wait 1 event cycle for that process to complete.

I am doing this because my data model notifies the mediators when it is registered and ready for use. Since the view is not usable when it is created we hide it with _visible for now.

 
class view.components.StopWatchView extends View
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.components.StopWatchView"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
 
 
	}
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
 
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function StopWatchView() 
	{
		super();
 
		_visible = false
 
	}
 
	private function ready () {
		stop()
 
		dispatchEvent (new UIEvent (this, UIEvent.READY, null, null));
 
	}
 
 
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
	public function getStringDescription():String 
	{
		return StopWatchView.stringDescription
	}
 
}

StopWatchViewMediator.as

An instance of this mediator is created when an instance of StopWatchView is created and added to the display. It observes its view component for a UIEvent.READY and dispatches a new instance of the same event to the context. This is done to prevent event crosstalk between the context and the view.

The view observes the context for an StopWatchModelEvent.REGISTER event. When this event is heard we know that the data tier has been set up and we can make the views available to the user.  In this case that means making the views visible in readyHandler().

class view.StopWatchViewMediator extends Mediator
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.StopWatchViewMediator"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}	
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
 
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function StopWatchViewMediator() 
	{
		super();
 
	}
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
	//override
	public function onRegister():Void 
	{
		addViewObserver (UIEvent.READY, uiReadyHandler);
		addContextObserver (StopWatchModelEvent.REGISTER, readyHandler);
	}
 
	private function uiReadyHandler(e:UIEvent):Void 
	{
		dispatchEvent (new UIEvent (this,UIEvent.READY,null,null))
	}
 
	//override
	public function onRemove ():Void {
 
 
	}
 
	private function readyHandler(e:StopWatchModelEvent):Void 
	{
		MovieClip (_viewComponent)._visible = true
 
	}	
 
 
 
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
 
	public function getStringDescription():String 
	{
		return StopWatchViewMediator.stringDescription
	}
 
 
}

TimeDisplayView.as

This is the view that shows the actual time display. It is just a MovieClip that wraps a TextField called _timeDisplay. It provides a function to update the text inside that TextField. In order to keep the view reusable it does not do any of the time formatting itself.

class view.components.TimeDisplayView extends View
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.components.TimeDisplayView"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
 
 
	}
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
 
	private var _timeDisplay:TextField
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function TimeDisplayView() 
	{
		super();
 
 
	}
 
	/**
	 * update the time display
	 * @param	value the time in Milliseconds
	 */
	public function updateTime (value:String) {
 
 
		_timeDisplay.text = value
 
	}
 
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
	public function getStringDescription():String 
	{
		return TimeDisplayView.stringDescription
	}
 
}

TimeDisplayMediator.as

This mediator observes StopWatchModelEvent.DATA_CHANGE events that come from the model when the time changes. This event carries the time in milliseconds as its payload. When that event is received dataHandler() is called to convert the time number into a  usable string format via a utility class TimeFormatUtil.as and update the view component. Notice that we have to cast _viewComponent to its more specific type TimeDisplayView since it is typed as IView in Mediator.as, which TimeDisplayMediator extends.

class view.TimeDisplayMediator extends Mediator
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.TimeDisplayMediator"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}	
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
 
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function TimeDisplayMediator() 
	{
		super();
 
	}
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
	//override
	public function onRegister():Void 
	{
		addContextObserver (StopWatchModelEvent.DATA_CHANGE, dataHandler)
 
 
		TimeDisplayView (_viewComponent).updateTime(TimeFormatUtil.millisecondToTime (0) )
	}
 
 
 
	//override
	public function onRemove ():Void {
 
 
	}
 
	private function dataHandler(e:StopWatchModelEvent):Void 
	{
 
		var time:Number = e.getBody()
 
		var timeString:String = TimeFormatUtil.millisecondToTime (time)
 
 
 
		TimeDisplayView (_viewComponent).updateTime(timeString )
	}
 
 
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
 
	public function getStringDescription():String 
	{
		return TimeDisplayMediator.stringDescription
	}
 
 
}

LapsDisplayView.as

Our StopWatch has the ability to record lap times. This view is intended to display those lap times. It is a MovieClip that wraps a TextField and provides a method to update the text, setLapText(). Like TimeDisplayView, the view is kept as generic as possible so it can be reused.

class view.components.LapsDisplayView extends View
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.components.LapsDisplayView"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
 
 
	}
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
	private var _timeDisplay:TextField
 
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function LapsDisplayView() 
	{
		super();
 
 
	}
 
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
 
	public function setLapText (value:String) {
 
		_timeDisplay.text = value
 
	}
 
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
	public function getStringDescription():String 
	{
		return LapsDisplayView.stringDescription
	}
 
}

LapsDisplayMediator.as

LapsDisplayMediator observes 2 events from the context. StopWatchModelEvent.LAP and StopWatchModelEvent.RESET and updates the view component as needed.

When the stopwatch is reset, we need to clear the display of the previous laps, this is done when StopWatchModelEvent.RESET is dispatched and the resetHandler function is called.

Each time the data model records a new lap, StopWatchModelEvent.LAP is dispatched and the view is updated by calling lapHandler().

class view.LapsDisplayMediator extends Mediator
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.LapsDisplayMediator"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}	
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
 
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function LapsDisplayMediator() 
	{
		super();
 
	}
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
	//override
	public function onRegister():Void 
	{
		addContextObserver (StopWatchModelEvent.LAP, lapHandler)
 
		addContextObserver (StopWatchModelEvent.RESET, resetHandler)
		LapsDisplayView (_viewComponent).setLapText (TimeFormatUtil.millisecondToTime (0))
 
	}
 
 
 
	//override
	public function onRemove ():Void {
 
 
	}
 
 
	private function resetHandler(e:StopWatchModelEvent):Void 
	{
		LapsDisplayView (_viewComponent).setLapText (TimeFormatUtil.millisecondToTime (0))
	}
 
 
	private function lapHandler(e:StopWatchModelEvent):Void 
	{
 
		var lapsArray:Array = e.getBody()
 
		var text:String
		for (var i:Number = 0; i <lapsArray.length ; i++) 
		 {
			 text += TimeFormatUtil.millisecondToTime (lapsArray[i]) + "\n";
		 } 
 
 
		LapsDisplayView (_viewComponent).setLapText (text)
 
 
	}
 
 
 
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
 
	public function getStringDescription():String 
	{
		return LapsDisplayMediator.stringDescription
	}
 
 
}

Buttons, StopWatchButton.as and Extensions

The StopWatch has 4 simple buttons that all need the same functionality. So I created StopWatchButton to serve as the base class for all 4. I then needed to handle the individual classes for each button. I could have added an interface to StopWatchButton to do this but since AS2 has not base class linkage in the IDE I would have had all 4 buttons implementing the same class. So I choose to extend StopWatchButton.as into 4 concrete button classes for each button. This is a little redundant but if I need to make the views more diverse later it is already set up, so it’s just a style choice.

Since this button is interactive we create 2 methods to turn that interactivity on and off, enableButton() and disableButton(). I am using custom methods here to make sure we are affecting the event handlers in the MicroMVC side of the view, not the native AS2 events.

class view.components.StopWatchButton extends View
{
	// ************************************************************************************
	// Class Level Vars
	// ************************************************************************************	
	private static var _stringDescription:String = "view.components.StopWatchButton"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
 
 
	}
	// ************************************************************************************
	// Instance Vars
	// ************************************************************************************	
 
	// ************************************************************************************
	// Constructor
	// ************************************************************************************		
	public function StopWatchButton() 
	{
		super();
 
 
	}
 
	public function enableButton () {
 
		enableEvents ([MovieClipEvent.RELEASE])	
		_alpha = 100
		useHandCursor = true
	}
 
	public function disableButton() {
 
		disableEvents ([MovieClipEvent.RELEASE])	
 
		_alpha = 50
		useHandCursor = false
	}
 
 
	// ************************************************************************************
	// Methods
	// ************************************************************************************		
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy ()
 
	}
 
	public function getStringDescription():String 
	{
		return StopWatchButton.stringDescription
	}
 
}

SetUpViewCommand.as

While technically part of the command tier i am discussing SetUpViewCommand now since it is used to bootstrap the view tier from our context. This command creates all our mediator / view relationships, then attaches an instance of our base view (StopWatchView.as) to the context view. Since this is AS2 and adding views is kinda lame we use the casalib.org MovieClipUtil class to help with that.

You should always attach views after your mediators maps are set so that you don’t miss catching the events as they bubble up the display list.

class control.SetUpViewCommand extends Command
{
	private static var _stringDescription:String = "control.SetUpViewCommand"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}
	public function SetUpViewCommand() 
	{
		super();
 
	}
 
	public function execute(context:IContext,payLoad:IEvent) 
	{
 
 
	context.getMediatorMap().mapView (StartButton.stringDescription, StartButtonMediator.stringDescription, true, true)
	context.getMediatorMap().mapView (StopButton.stringDescription, StopButtonMediator.stringDescription, true, true)
	context.getMediatorMap().mapView (LapButton.stringDescription, LapButtonMediator.stringDescription, true, true)
	context.getMediatorMap().mapView (ResetButton.stringDescription, ResetButtonMediator.stringDescription, true, true)
	context.getMediatorMap().mapView (TimeDisplayView.stringDescription, TimeDisplayMediator.stringDescription, true, true)	
	context.getMediatorMap().mapView (LapsDisplayView.stringDescription, LapsDisplayMediator.stringDescription, true, true)	
	context.getMediatorMap().mapView (StopWatchView.stringDescription, StopWatchViewMediator.stringDescription, true, true)	
 
 
 
 
	MovieClipUtil.attachMovie (MovieClip (context.getContextView()), "StopWatchView", "_StopWatchView");
 
 
 
 
	}
 
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy()
	}
 
	public function getStringDescription():String 
	{
		return SetUpViewCommand.stringDescription
	}
 
}

Setting Up the Model Tier

Since I chose to do the view tier first I do the model tier next, you could also reverse this order if you want. There is also a difference in set up order and design order. In some cases it makes more sense to design the model tier first so you know what events are being dispatched, and others you design the view tier first.

The model tier consists of a class that stores all our data and acts as a timer and a class for the events our model will dispatch.

StopWatchModel.as

StopWatchModel stores all the data for our application. Its main function is to run a interval timer and dispatch events when the data is updated. It does not store its state per say, instead it dispatches events and those events indicate which state it is in.

Let’s look at the variables first:

  • _intervalTimer is a number to store the AS2 interval
  • _intervalCount is the number of times the interval has completed
  • _intervalMillisecondDuration is the duration of each tick, by changing this we can create different types of timers
  • _lapArray stores laps

StopWatchModel has several functions to change its data and state. Each of these dispatches an event to notify the application that something has changed.

startTimer()
creates a new interval and starts it running. We have to use mx.utils.Delegate there since we are using the built in AS2 timer.

stopTimer()
Stops the interval

Reset()
Stops the interval, resets all the data back to its defaults and sends out an event.

addLap()
Stores the current time in an array

timerHandler()
Adds 1 to the interval count each time the interval completes

set intervalCount()
We provide access to the private var _intervalCount via this a get and set function. When the value is set we dispatch an event that the data has changed.

Get time()
Is a helper function to get the total time which is _intervalCount * _intervalMillisecondDuration

onRegister()
This is an override of the same method in Actor.as. We dispatch an event to notify the rest of the system when the model is ready.

onRemove()
This is an override of the same method in Actor.as. We dispatch an event to notify the rest of the system when the model is removed.

class model.StopWatchModel extends Actor
{
	private static var _stringDescription:String = "model.StopWatchModel"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}	
 
 
 
	// for the SetInterval
	private var _intervalTimer:Number = 0
 
	// # of 100 millisecond (.1 sec) units that have passed
	private var _intervalCount:Number = 0
	// holds the laps
	private var _lapArray:Array = new Array ()
	// the duration of each tick. 100 ms 
	private var _intervalMillisecondDuration:Number = 100
 
	public function StopWatchModel(eventDispatcher:IEventDispatcher) 
	{
		super(eventDispatcher);
 
	}
 
	public function startTimer ():Void {
 
 
		_intervalTimer = setInterval (Delegate.create (this, timerHandler    ),_intervalMillisecondDuration);
		dispatchEvent (new StopWatchModelEvent (this,StopWatchModelEvent.START,time,null))
 
	}
 
	public function stopTimer ():Void {
 
		clearInterval (_intervalTimer)
		dispatchEvent (new StopWatchModelEvent (this,StopWatchModelEvent.STOP,time,null))
 
 
	}
 
	public function reset():Void {
 
		clearInterval (_intervalTimer)
 
 
		intervalCount = 0
 
		_lapArray = new Array()
 
		dispatchEvent (new StopWatchModelEvent (this,StopWatchModelEvent.RESET,time,null))
 
 
	}
 
	public function addLap() {
 
		_lapArray.push (time)
		dispatchEvent (new StopWatchModelEvent (this, StopWatchModelEvent.LAP, lapArray, null));
	}
 
 
	private function timerHandler():Void 
	{
 
		intervalCount++
 
 
	}
 
 
 
 
	public function get intervalCount():Number { return _intervalCount; }
 
	public function set intervalCount(value:Number):Void 
	{
		_intervalCount = value;
 
		dispatchEvent (new StopWatchModelEvent (this, StopWatchModelEvent.DATA_CHANGE, time, null));
	}
 
 
	public function get time ():Number {
 
		return _intervalCount * _intervalMillisecondDuration
 
	}
 
	public function get lapArray():Array { return _lapArray; }
 
 
 
	public function onRegister():Void 
	{
 
 
		dispatchEvent (new StopWatchModelEvent(this,StopWatchModelEvent.REGISTER,null,null))
 
 
	}
	public function onRemove():Void 
	{
 
 
		dispatchEvent (new StopWatchModelEvent (this,StopWatchModelEvent.REMOVE,null,null))
 
	}
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy()
	}
 
	public function getStringDescription():String 
	{
		return StopWatchModel.stringDescription
	}
 
}

StopWatchModelEvent.as

This class contains all the event types used by the data model. The payload of each event is determined by the model when it is dispatched.

class model.StopWatchModelEvent extends Event
{
	private static var _stringDescription:String = "model.StopWatchModelEvent"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}	
 
	public static var DATA_CHANGE:String 		=_stringDescription+ " "+ 'data change';
	public static var REGISTER:String 		=_stringDescription+ " "+ 'register';
	public static var REMOVE:String 		= _stringDescription + " " + 'remove';
	public static var START:String 			= _stringDescription + " " + 'start'; 
	public static var STOP:String 			= _stringDescription + " " + 'stop'; 
	public static var RESET:String			= _stringDescription + " " + 'reset';
	public static var LAP:String			= _stringDescription + " " + 'lap';
 
 
	public function StopWatchModelEvent(p_target:Object, p_type:String, p_body, p_note:String) 
	{
		super(p_target, p_type, p_body, p_note);
 
	}
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
	super.destroy()	
	}
 
	public function getStringDescription():String 
	{
		return StopWatchModelEvent.stringDescription
	}
 
}

SetUpModelCommand.as

Once we have our model tier set up, we create the instances we need with SetUpModelCommand.as. All we need to do is create an instance of StopWatchModel and register it in the ActorMap. Once it is registered its event StopWatchModelEvent.REGISTER will be observed by StopWatchViewMediator.as and the views will be made visible.

Note that in the context the CommandMap relationship is made to UIEvent.READY not ContextEvent.STARTUP_COMPLETE. This is so we know the views are ready to be used before we create the model tier.

class control.SetUpModelCommand extends Command
{
	private static var _stringDescription:String = "control.SetUpModelCommand"
	public static function get stringDescription ():String {
 
		return _stringDescription
 
	}
	public function SetUpModelCommand() 
	{
		super();
 
	}
 
	public function execute(context:IContext,payLoad:IEvent) 
	{
 
 
		var swm:StopWatchModel = new StopWatchModel (context.getEventDispatcher());
 
 
		context.getActorMap().registerActor (swm, "stopWatchModel")
 
 
 
 
	}
 
 
	/* INTERFACE com.MicroMVC.core.ICoreObject */
 
	public function destroy():Void 
	{
		super.destroy()
	}
 
	public function getStringDescription():String 
	{
		return SetUpModelCommand.stringDescription
	}
 
}

Setting Up the Command Tier

The purpose of the command tier is to update the model based on events dispatched from the view tier. Using commands keep the logic of updating the model separate from the views, so if the model API changes you can just update the commands instead of the views. In our StopWatch example we have a command to respond to each event dispatched from the view tier. In order to keep the post shorter I will only post the contents of the execute() function of each command. These command classes are mapped to the specific event strings not specific view classes; so they respond whenever the right event type is dispatched, regardless of where it came from.

UIStartCommand.as (responds to UIEvent.START)

UIStartCommand tells StopWatchModel to start keeping time. We retrieve the model from the ActorMap and call the startTimer() method.

	public function execute(context:IContext,payLoad:IEvent) 
	{
 
		var swm:StopWatchModel = StopWatchModel (context.getActorMap().retrieveActor ("stopWatchModel"))
 
		swm.startTimer()
 
	}

UIStopCommand.as (responds to UIEvent.STOP)

UIStopCommand tells StopWatchModel to stop keeping time.

public function execute(context:IContext,payLoad:IEvent) 
	{
 
		var swm:StopWatchModel = StopWatchModel (context.getActorMap().retrieveActor ("stopWatchModel"))
 
		swm.stopTimer()
 
	}

UIResetCommand.as (responds to UIEvent.RESET)

UIResetCommand tells StopWatchModel to reset, this stops the timer and zeros out the time and laps.

public function execute(context:IContext,payLoad:IEvent) 
	{
 
		var swm:StopWatchModel = StopWatchModel (context.getActorMap().retrieveActor ("stopWatchModel"))
 
		swm.reset()
 
	}

LapCommand.as (responds to UIEvent.LAP)

LapCommand tells StopWatchModel to add a lap to its lap array

public function execute(context:IContext,payLoad:IEvent) 
	{
 
 
 
		var swm:StopWatchModel = StopWatchModel (context.getActorMap().retrieveActor ("stopWatchModel"))
 
		swm.addLap()
 
	}

SetUpControlCommand.as

SetUpControlCommand maps all the relationships between UIEvents and their various Commands.

public function execute(context:IContext,payLoad:IEvent) 
	{
		context.getCommandMap().mapEvent (UIEvent.START,UIStartCommand.stringDescription)
		context.getCommandMap().mapEvent (UIEvent.STOP,UIStopCommand.stringDescription)
		context.getCommandMap().mapEvent (UIEvent.RESET,UIResetCommand.stringDescription)
		context.getCommandMap().mapEvent (UIEvent.LAP,LapCommand.stringDescription)
 
	}

Source

The source for this project can be found here.

The project also requires our MicroMVC platform.

Line

Leave a Reply

*

Line
Line
Pony