These slides are from a presentation at Flex London User Group on 16 February 2010.
With so many application frameworks available which should you choose? Cairngorm? PureMVC? Mate? Swiz? Parsley? Robotlegs? Or should you roll your own? Which frameworks require you to write the most code? Which provide the easiest refactoring? Which features make frameworks flexible and which make them brittle? Which make them easy to use and which make them hard?
Richard presents an overview of how the different frameworks are architected and looks at their good and bad features. He looks at the core architecture of each, how they handle dependencies and events and the different philosophies that drive each forward.
If you’'re interested in architecture, frameworks, or design patterns, this will be of interest to you. If you need to choose a framework for a project, or you want to know more about the framework you are using, this will be essential viewing.
5. Managing Dependencies
Model
View
Model
Model
View
View
Controller Controller Controller
6. Cairngorm uses global singletons
Model Singleton
View
Model Model Model
View
View
Controller Controller Controller
7. Cairngorm uses a Singleton
Model is a Singleton
class ModelLocator implements IModelLocator {
public static function getInstance():ModelLocator {
...
}
[Bindable]
public var user:User;
}
View / Controller access that Singleton
var user:User = ModelLocator.getInstance().user;
8. PureMVC uses a registry
Model
View
Model
Model
View
Model Registry
View
Controller Controller Controller
9. Accessing the model in Pure MVC
Model is a registry of proxies
class UserProxy extends Proxy implements IProxy {
public function get user():User {
...
} Add object to registry
}
facade.registerProxy( new UserProxy() );
View / Controller fetch proxies from the registry
var userProxy:UserProxy = facade.retrieveProxy( "UserProxy" )
as UserProxy;
var user:User = userProxy.user;
Fetch object from registry
10. Others use dependency injection
Model
View
Model
Model Dependency View
Injection
Container
View
Controller Controller Controller
11. Accessing the model in Mate
Injection rules are defined in EventMaps
<mx:Script>
modelManager = new ModelManager();
modelManager.user = new User(); The Model is one or
</mx:Script> more regular objects
<Injectors target="{ProfileView}">
<PropertyInjector source="{ModelManager}" sourceKey="user"
targetKey="user"/>
</Injectors>
Define injection rules
Properties are injected into the view
public class ProfileView {
public var user:User; This will be set by
//...
}
the DI container
12. Accessing the model in Swiz
Injection rules are defined in BeanLoaders
<BeanLoader>
<User id="user"/>
</BeanLoader> Regular object
defined in MXML
BeanLoaders are instatiated in your application
<SwizConfig beanLoaders="{[MyBeans]}">
Objects specify their requirements
[Autowire]
public var user:User; And injected into
other objects
13. Accessing the model in RobotLegs
Injection rules are defined in a context
class MyAppContext {
override public function startup():void {
injector.mapSingleton( User );
}
Injection rules are
} defined in the context
Context is instatiated in your application
<MyAppContext contextView="{this}">
Objects specify their requirements
[Inject]
public var user:User; And injected into
other objects
14. Accessing the model in Parsley
Injection rules are defined in a configuration object
<mx:Object>
<User id="user"/> Model objects
</mx:Object> are created in a config
object
Configuration object is instatiated in your application
<ContextBuilder config="{MyAppConfig}">
Objects specify their requirements
[Inject]
public var user:User; And injected into
other objects
17. Event Bus
View View View
Event Bus
Controller Controller Controller
18. Using a single event dispatcher
View View View
Event
Dispatcher
Controller Controller Controller
19. Using a single event dispatcher
View
var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN);
loginEvent.username = username.text;
loginEvent.password = password.text;
singleEventDispatcher.dispatchEvent( loginEvent );
Controller
singleEventDispatcher.addEventListener( LoginEvent.LOGIN,
loginHandler )
20. View-Controller in Cairngorm
extends CairngormEvent
View
var loginEvent:LoginEvent = new LoginEvent( LoginEvent.LOGIN );
loginEvent.username = username.text;
loginEvent.password = password.text;
loginEvent.dispatchEvent();
Front Controller
addCommand( LoginEvent.LOGIN, LoginCommand );
Command
public class LoginCommand extends Command {
public function execute( event:Event ):void {
var loginEvent:LoginEvent = event as LoginEvent;
...
}
}
21. View-Controller in Pure MVC
View Notifications are
var loginData:LoginData = new LoginData(); like Events
loginData.username = username.text;
loginData.password = password.text;
sendNotification( NotificationNames.LOGIN, loginData );
Controller
registerCommand( NotificationNames.LOGIN, LoginCommand );
Command
public class LoginCommand extends SimpleCommand {
public function execute( note:INotification ):void {
var loginData: LoginData = note.getBody() as LoginData;
...
}
}
22. View-Controller in RobotLegs
View
var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN);
loginEvent.username = username.text;
loginEvent.password = password.text; Reference to
eventDispatcher.dispatchEvent( loginEvent ); central dispatcher is
injected
Context
commandMap.mapEvent( LoginCommand, LoginEvent.LOGIN );
Command
public class LoginCommand extends Command {
[Inject]
public var event:LoginEvent;
public function execute():void {
...
}
}
23. View-Controller in Parsley
Central dispatcher will
View redispatch this event
[Event(name="login",type="LoginEvent")]
[ManagedEvents("login")]
var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN);
loginEvent.username = username.text;
loginEvent.password = password.text;
dispatchEvent( loginEvent );
Configuration
<DynamicCommand type="" selector="login"/>
Command
public class LoginCommand {
public function execute( event:LoginEvent ):void {
...
}
}
24. View-Controller in Parsley II
Central dispatcher will
View redispatch this event
[Event(name="login",type="LoginEvent")]
[ManagedEvents("login")]
var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN);
loginEvent.username = username.text;
loginEvent.password = password.text;
dispatchEvent( loginEvent );
The method
Controller handles this event
[MessageHandler(selector="login")]
public function loginHandler( event:LoginEvent ):void {
...
}
25. Using the display list
Add listeners here
System Manager
Application Pop-up
Display Object Display Object Module
Display Object Display Object Display Object
Display Object Display Object Display Object
26. View-Controller in Swiz
View
var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN, true);
loginEvent.username = username.text;
loginEvent.password = password.text;
dispatchEvent( loginEvent );
Bubbling
Event
Controller
[Mediate(event="LoginEvent.LOGIN")]
public function loginHandler( event:LoginEvent ):void {
...
}
27. View-Controller in Mate
View
var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN, true);
loginEvent.username = username.text;
loginEvent.password = password.text;
dispatchEvent( loginEvent );
Bubbling
Event
Event Map
<EventHandlers type="{LoginEvent.LOGIN}">
...
</EventHandlers>
28. Mate has local event maps
Main event map
System Manager
Application Pop-up
Display Object Display Object Module
Local event map
Display Object Display Object Display Object
Display Object Display Object Display Object
29. Event Bus
Single Event Dispatcher
(may have multiple with access method)
Display List
(may use localised event handling)