-
Notifications
You must be signed in to change notification settings - Fork 0
#Building MVC Architectures
Parsley is different from several other Flex or Flash MVC Frameworks in that it does not provide very much explicit support for the various pieces of an MVC architecture. This was a side effect of our primary goal being to allow to design a fully decoupled architecture. Decoupled in a sense that not only the parts of your application are decoupled from each other, but also decoupled from the framework itself. For example providing base classes for controllers or mediators in the framework that application classes have to extend is a bad idea if you want to support such a decoupled architecture.
For that reason the Messaging Framework in Parsley which we already described in Messaging is pretty generic. It does not assume a particular programming style or architectural pattern. Nevertheless Parsley still falls into the same category as many other MVC Frameworks since the Messaging Framework can easily be used in a way that helps building an application based on the MVC architectural pattern. In this chapter we will provide some examples on how to use the Messaging Framework in such a context.
##MVC Event Flow Example
The following diagram shows an example flow for a particular use case (user adds item to shopping cart) in the context of a Parsley MVC application:
Explanations for the numbered steps from the diagram:
-
1: The user clicks the "Add to cart" button. With Flex for example this will generate a low level UI event. The event handler in the component invokes a method on the presentation model instance (usually injected into the view) which handles communication between View and Controller.
-
2: The model creates an application message possibly gathering any further information from the view and encapsulating this information in the message. This message will then be dispatched through Parsleys
MessageRouter
-
3: The
MessageRouter
will then process any MessageHandlers or Commands which were registered for this message type (usually with Metadata tags on methods or properties, alternatively in MXML or XML). In this case theAddToCartCommand
will be invoked. -
4: The command will invoke a remote service method (the service usually being injected). The asynchronous operation will be managed by the framework which allows to avoid some of the usual plumbing code. Neither the command nor any other part of the application has to explicitly add a result handler to the AsyncToken returned by the remote call.
-
5: The framework receives the result. It is first returned to the command instance itself if it contains a result handler. But this is purely optional.
-
6: The result handler in the command might modify or cache the model before it gets passed to other result handlers.
-
7: Next the framework will invoke any other registered result handlers in the application. In this case the CartPM contains a result handler which will now be invoked causing the model instance to update its internal state.
-
8: The view is refreshed, usually through binding to properties of the presentation model.
From the example above many core elements will have been setup and wired in a
Parsley Context
including the view as described in Dynamic View Wiring.
This usually includes all controller actions, their dependencies like remote services,
and the registration for particular messages in the MessageRouter
.
If you think this diagram smells like over-engineering, it merely serves as an example for a full blown MVC architecture of a large and complex application. In smaller and simpler applications you can of course simplify the design presented above.
##Example Command Implementation
Finally we'll pick one of the pieces presented in the diagram above and show
how the implementation and configuration of such an application part may look like.
We'll chose the AddToCartCommand
that participates in the application flow shown in the diagram.
package com.bookstore.actions {
import mx.rpc.AsyncToken;
import mx.rpc.Fault;
import mx.rpc.remoting.RemoteObject;
import com.bookstore.messages.AddToCartMessage;
import com.bookstore.services.CartService;
import com.bookstore.model.LineItem;
public class AddToCartCommand {
[Inject(id="cartService")]
public var cartService:RemoteObject;
public function execute (message: AddToCartMessage): AsyncToken {
return cartService.addItem(message.item);
}
public function result (item: LineItem): void {
/* modify or cache the result */
}
public function error (fault: Fault): void {
/* handle fault */
}
}
}
And this is how you can map such a command to a message in a Parsley configuration class (in this case MXML):
<parsley:MapCommand type="{AddToCartCommand}" />
We'll now examine the various parts of this class in detail. First there is the method that executes the command:
public function execute (event: AddToCartMessage) : AsyncToken {
The method parameter tells the framework that we are interested
in AddToCartMessage
. MessageHandler selection happens based on message type, so in a large and complex application
you won't run into problems having to maintain event type constants which are unique across the whole system.
In the body of that method we are using the injected CartService
:
[Inject(id="cartService")]
public var cartService:RemoteObject;
In this example we are using a RemoteObject. We usually prefer to use injection by type but this is not applicable for RemoteObjects which can only be distinguished by id. For details see Remoting.
Finally there are the result and error handlers:
public function result (item:LineItem) : void {
public function error (fault:Fault) : void {
We are following a naming convention here so we can avoid any metadata configuration altogether. Based on the method names the framework knows which method executes the command and which handles results or faults. The result and error handler are both optional.
- Features List
- What's New in Parsley 3.0
- Migrating from Parsley 2 to Parsley 3
- Building the Framework from Source
- Dependencies
- Hello World Sample Application
- Adding the Framework SWCs
- Defining Object Dependencies
- Sending and Receiving Messages
- Assembling the Objects
- Initializing the Framework
- Adding more Services
Configuration and Initialization
- Configuration with AS3 Metadata
- MXML Configuration
- XML Configuration Files
- Runtime Configuration
- Configuration DSL
- ActionScript Configuration
- Combining multiple Configuration mechanisms
- Configuration Properties
- Constructor Injection
- Method Injection
- Property Injection by Type
- Property Injection by Id
- Declaring Dependencies in MXML or XML
- Overriding Dependencies in Child Contexts
- Comparing Dependency Injection and Decoupled Bindings
- Basic Usage
- Avoiding Conflicts
- Using Scopes
- Publishing Managed Objects
- Persistent Properties
- Bindings in Flash
- Dispatching Messages
- Receiving Messages
- Managed Events
- Injected MessageDispatchers
- MessageHandlers
- MessageBindings
- Intercepting Messages
- Error Handlers
- Using Selectors
- Using Scopes
- Using the Messaging API
- Implementing a Command
- Mapping Commands to Messages
- Command Groups
- Command Flows
- Starting a Command Programmatically
- Handling Results and Observing Commands
- Command Lifecycle
- About Managed Objects
- Using Factories
- Asynchronous Object Initialization
- Object Initialization Order
- Object Lifecycle Methods
- Lifecycle Observer Methods
- Dynamic Objects
- Initializing View Wiring Support
- Explicit Component Wiring
- Component Wiring without Reflection
- Automatic Component Wiring
- Metadata Configuration
- MXML and XML Configuration
- Component Lifecycle
- Flex Popups and Native AIR Windows
- View Wiring in Modular Applications
- Available Extension Points
- Custom Metadata Tags
- Custom MXML and XML Tags
- Working with ObjectDefinitions
- Working with Scopes
- Custom Configuration Mechanisms
- Replacing IOC Kernel Services
- Initializing Extension Modules