PureMVC has been my framework of choice for the last 18 months, the beginning of our relationship was a bit rocky but after a while we got to know each outher. Now, looking back at atleast the ten bigger projects I have done since, I'd say we know one another well, so well that I have learned a bunch of new hints and tips. Something I thought I might aswell share on this blog.
Im not only making this little article as a reflection of my past experiences, but also to mark a new start for me with my new framework of choice RobotLegs, and this felt like a good way to end things :) In time I might go back to using PureMVC, perhaps not. PureMVC is anyway a great framework and alot of fun, so I hope some of these puremvc tips comes in handy!
1. Dare to use Proxies
The hardest part for me was to use Proxies. In the beginning I often ended up using a mediator when I could have used a proxy instead. Take a look at these examples.
SizeProxy = This Proxy listens for stage resize events and sends out resize notifications all through the application. In the past I embedded this functionality into a mediator called ApplicationMediator.
AddressProxy = This Proxy takes care of all state management related data, and do everything from setting, retriving, formatting and finally sending out notifications. In the past I had this functionality into a mediator aswell. (Shame on me!)
2. Keeping track of your proxies and mediators
Avoid always re-typing string representations when dealing with proxies and mediators. Add a static constant variable named NAME in your classes and refer to that variable any time you need to access the proxy/mediator. Like this.
The class
package se.marteinn.puremvc.single.view
{
import org.puremvc.as3.interfaces.IMediator;
import org.puremvc.as3.patterns.mediator.Mediator;
public class ApplicationMediator extends Mediator implements IMediator
{
public static const NAME:String = "applicationMediator";
}
}
Registrating the mediator
this.facade.registerMediator( new ApplicationMediator( ApplicationMediator.NAME, application ) );
Retriving the mediator
this.facade.retriveMediator( ApplicationMediator.NAME ) as ApplicationMediator
Aww, you get the idea!
3. Dont forget your OOP
Remember that Mediators are still classes that you can extend. So dont be afraid to make your own “abstract” classes.
Like this
package se.marteinn.puremvc.single.view.states
{
import org.puremvc.as3.interfaces.IMediator;
import org.puremvc.as3.patterns.mediator.Mediator;
public class StateMediator extends Mediator implements IMediator
{
public function StateMediator(mediatorName:String=null, viewComponent:Object=null)
{
super(mediatorName, viewComponent);
}
public function singJohnnyCash ()
{
trace( “Ring of fire” );
}
}
}
And then extending it.
package se.marteinn.puremvc.single.view.states
{
import se.marteinn.puremvc.single.view.states.StateMediator;
import org.puremvc.as3.interfaces.IMediator;
public class PageStateMediator extends StateMediator implements IMediator
{
public function PageStateMediator(mediatorName:String=null, viewComponent:Object=null)
{
super(mediatorName, viewComponent);
singJohnnyCash();
}
}
}
4a. Be nice to the commands
Keep them as clear and as re-usable as possible. Try not to manipulate mediators directly in the command, use notifications instead. (Since its all ok for a mediator to retrive notifications).
4b. But use a command whenever you can
Commands makes your application easier to understand and to work with, so use commands whenever it feels right.
5. Organizing notifications
Placing all notifications into one class (placed in the application root) helps keeping track of things.
package se.marteinn.puremvc.single
{
public class ApplicationNotifications
{
public static const STARTUP:String = "startup";
// preload related
public static const INIT_PRELOAD:String = "initPreload";
public static const START_PRELOAD:String = "startPreload";
public static const LOAD_CONFIG:String = "loadConfig";
public static const CONFIG_LOADED:String = "configLoaded";
// yada yada..
}
}
And its easy to access
sendNotification( ApplicationNotifications. STARTUP );
6. Organizing parameters
To place values the application needs to actually work, such as api keys and values you dont want to store in a external config file, into its own class is a good idea.
package se.marteinn.puremvc.single
{
public class ApplicationParameters
{
public static const GOOGLE_MAPS_API_KEY:String = "asd234234dssdf";
}
}
And its easy to access
loadStuff( ApplicationParameters. GOOGLE_MAPS_API_KEY );
7. Use onRegister whenever you can on your proxies and mediators
My advice is not to place construction code into the constructor of proxies/methods, instead override the onRegister method and place your code there. It makes you code easier to read and give you less bugs in the future (when porting a app to multicore). Read more here http://lowpitch.com/blog/puremvc-multicore-vs-standard-singlecore/
8. The namespace
So, how should a PureMVC namespace be organized? Well, a namespace can be organized in many forms, this is my way in doing it.
se.marteinn.project
controller
vo
(My controller specific VO:s here)
(My commands here)
model
vo
(My model specific VO:s here)
services
(My model specific services here)
(My proxies here)
view
components
(View related components here)
(My mediators here)
ApplicationFacade
ApplicationNotifications
ApplicationParams
It could also look like this:
se.marteinn.project
controller
vo
(My controller specific VO:s here)
commands
(My commands here)
model
vo
(My model specific VO:s here)
services
(My model specific services here)
proxies
(My proxies here)
view
components
(View related components here)
mediators
(My mediators here)
ApplicationFacade
ApplicationNotifications
ApplicationParams
9. Adding a interface to the application main class
To make things as flexible as possible and to simplify when installing my puremvc base into a new application, I have a interface called IApplication, where the main Application implements IApplication. That way:
The application class can be named whatever, as long its implementing IApplication...
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import se.marteinn.puremvc.single.IApplication;
[SWF(frameRate="31", backgroundColor="#000000")]
public class TestApp extends Sprite implements IApplication
{
protected function draw () : void
{
ApplicationFacade.getInstance().startup( this );
}
}
}
...the facade will be fine with it
package se.birth.puremvc.single
{
import org.puremvc.as3.interfaces.IFacade;
import org.puremvc.as3.patterns.facade.Facade;
import se.marteinn.puremvc.single.controller.StartupCommand;
public class ApplicationFacade extends Facade implements IFacade
{
protected static var instance:ApplicationFacade;
public static function getInstance () : ApplicationFacade
{
if( instance == null )
instance = new ApplicationFacade ();
return instance;
}
override protected function initializeController():void
{
super.initializeController();
this.registerCommand( ApplicationNotifications.STARTUP, StartupCommand );
}
public function startup ( application:IApplication ) : void
{
this.sendNotification( ApplicationNotifications.STARTUP, application );
}
}
}
Read more
If you are looking for more advice and thoughts on how to build better PureMVC applications, look at these links:
10 tips for working with PureMVC by Jens Krause
http://www.flex-labs.de/blog/2008/10/10-tips-for-working-with-puremvc-by-jens-krause/
Building a Flash site using PureMVC
http://hubflanger.com/building-a-flash-site-using-puremvc/
My own PureMVC collection of links (both Singlecore and Multicore)
http://delicious.com/marteinn/puremvc
Last but not least, the PureMVC.org website with the all mighty guru of know it all Cliff Hall
http://www.puremvc.org/
Cheers!