This is the second in my series on my adventures learning about the robotlegs framework. In my first post I spoke about Article 2 focuses on the model, and that is what I will talk about in this article.
What is a Model?
If you've been around in the development world for a while, you've probably heard the term model. It is even part of the name of one of the most pervasive design patterns, Model View Controller, or MVC for short. A model usually contains data storage, often in a database level, and classes to load, and store, that data into memory. Your data is often stored in memory as 'dumb' objects, called Value Objects in the Cairngorm world and Data Transfer Objects in many other situations.
Often a Model is more than just a collection of dumb data containers, though. It will include objects that contain business logic and other application specific knowledge. One example may be a Shopping Cart object which probably contains a lot of data which is not analogous to a single database table. It also probably contains business logic such as the total price of all items in the cart.
In Cairngorm, there was a ModelLocator which would contain model objects. It was often a big data storage object. In the Cairngorm projects I worked n, the move was to have a single ModelLocator with all your global data in it. RobotLegs has directed me to a different approach.
Build out Multiple Models
In my RobotLegs development, I have been building multiple, focused, models. For the most part each model class I create is just a way to store data in memory for use in multiple places. In the current application I'm building, I have a model for search criteria, which stores the criteria a user entered into the search form. Based on that data, I may call any one of four different remote procedures to retrieve search results.
I also have a model for user authentication information. There is a model that contains Controlled Vocabulary dataProviders for ComboBoxes and Lists used across multiple forms. I like this approach because I'd rather have a lot of independent focused, objects instead of one big object with lots of unrelated data.
A sample Model may look like this
2{
3 import com.flextras.vo.UserVO;
4 import org.robotlegs.mvcs.Actor;
5
6 public class UserModel extends Actor
7 {
8 public function UserModel()
9 {
10 super();
11 }
12
13 public var user : UserVO;
14 }
15}
The model class is just a class like any other ActionScript class you're used to creating. Model extends the Actor class, which is a helper class included as part of the Robotlegs framework. Actor includes code for implementing the dispatch method. The dispatch method can be viewed as a parallel to Flex's dispatchEvent method. Where dispatchEvent uses the internal Flash Player mechanism to dispatch events to a component's parent, the Robotlegs dispatch method will dispatch events to the model's context. Mediators, as discussed in part one of this series, can listen to context events. This is a unique way to tell the rest of your application that something important happened. I'll expand more on context events in a later entry to this series.
Dependency Inject that Model!
Now that you've created the model class, what can you do with it? You'll want to add it into your mediators using Dependency Injection. Dependency injection is a design pattern that means the system will create objects for you automatically, and set them as instance variables on the objects that need them. To use Dependency injection with Robotlegs I've been following these steps:
- In your context, define the type of injection that occurs.
- In the mediator, define the variable with the inject metatag.
These are two simple steps, but they can be very powerful. First, in your context, you want to set up your object to be used for injection purposes. The context includes a variable called injector and injector has many methods for injecting the class. To inject the UserModel as a singleton, do this:
There are other forms of mapping, but I have stuck to mapSingleton for this project. The value of the map method is a class name. We do not create an instance of the class. The injector deals with that. In your mediator, you use the inject metadata to get your singleton instance into the mediator. Put the metadata before the variable that will represent your UserModel instance:
2public var user : UserModel;
The rest of the magic occurs automagically. At runtime, the injector knows to create a single instance of UserModel class. It knows to set the user property of our mediators to that single instance.
It is worth noting that Robotlegs uses swiftSuspenders under the hood for dependency injection. I have not spent any time exploring it in depth yet.
Once the model is in the mediator, what do you do with it? It depends on the type of data and how you want to do it. I have used models to pass search criteria into a service and I've used them to pass data into a view for display. I've also updated model data from the mediator.
A Review
So, let's see what is going on in a Robotlegs process:
- A component loads, and initializes the context.
- The context runs the startup procedure.
- The startup procedure prepares classes for dependency injection and maps mediators to views.
- After a display component is created, and added to the stage, Robotlegs creates it's mediator.
- RobotLegs injects all appropriate objects into the view's mediator
- The mediator's onRegister method executes.
How we make use of injection, models, and mediators will depend on what you want to accomplish with your application.
#1 by Stray on 1/28/11 - 1:40 PM
Generally, this is a better practice, as your mediator will be informed of changes to the model. You can also send out information in a much slimmer form - a focused VO that contains a few properties of the model for example.
You would Inject a model into a Command to update it or perform some operations, or even extract values via its API to pass to a service.
If you Inject your model into your mediator it's very easy to end up with messy logic spread over multiple mediators and problems keeping all your views in sync with the model. So while you're learning robotlegs I would suggest that you avoid this approach and stick with the shared eventDispatcher instead.
#2 by Tolis on 1/28/11 - 7:13 PM
Stray is it possible to give a link to an example of an eventDispatcher in action?
#3 by Jeffry Houser on 2/3/11 - 5:35 PM
Best practice are never subjective are they? ;)
What is the mediator eventDispatcher? Do you mean the 'dispatch' method implemented in the mediator? Or is it something entirely different?
I notice that you used model in the singular. When you build apps do you only have one model class?
I have been developing with plenty of model classes and each contains a discrete set of related information. The model class that I'm injecting into the mediator is already "small and focused".
For example, the userModel contains information on the user who logged in and nothing else.
My VOs often represent a single entity which I believe is common. My Model classes are a bit more complicated than that. They might contain an Array of those entities.
To date, in this application, I haven't had a situation where changes to a model need to affect a view in another part of the application. I'm not sure if this is due to the app I'm writing or the way I have architected the app.
As such, I'm not understanding your scenario with "messy logic" in multiple mediators; as I have none of that.
In relation to commands. Other than a reference or two in some code samples; I haven't found any documentation on using commands in Robotlegs. I can tell you a commandMap exists; but I couldn't tell you exactly what it is used for. At least not yet.