Tom Sugden: Applying the Presentation Model in Flex

« Best Practices for the Flex Logging Framework | Main | Eliminate Common Bad Practices with FlexPMD »

August 24, 2009

Applying the Presentation Model in Flex

Introduction

The purpose of the Presentation Model design pattern is simple to grasp: it’s a way of moving state and logic out of a view component and into another class, where it can be developed, comprehended and unit tested more easily. The pattern promotes a clean separation of concerns, helping to keep MXML views as structural definitions, free from Script-block logic. However, there are several ways to apply presentation models in Flex. Some of these can help us to build simpler, more testable systems, while others may lead towards entanglement and maintenance difficulties.

For a comprehensive introduction to the Presentation Model pattern and a comparison between it and other presentation patterns, please refer to Paul Williams' blog series on the topic. At Adobe Professional Services, we have found the Presentation Model to be well suited to Flex, since it takes advantage of language features like bindings and in-line event handlers, while side-stepping some of the difficulties of unit testing display objects.

This article discusses two approaches to applying the Presentation Model -- hierarchical and componentized -- and makes a recommendation in favour of the latter.

Two Approaches: Hierarchical or Componentized

Hierarchical

With the hierarchical approach to the Presentation Model (PM) pattern, a hierarchy of PMs is developed that reflects the hierarchy of view components, as shown in the Figure 1.

PM1.png

Figure 1 - A hierarchy of views and presentation models.

Each MXML view component has a corresponding PM. The parent view contains the child views, and likewise, the parent PM contains the child PMs. Below these View-to-PM pairs, there are only basic UI controls, implemented in ActionScript without corresponding PMs.

With this approach, the top-level PM is usually instantiated in the top level view. It may be a singleton to allow other parts of the application, such as commands to access it as required. The child PMs are then passed down manually into the child views, as shown below:

<example:MyComponent ... >
<mx:Script>
[Bindable] public var model:MyComponentPM;
</mx:Script>
<example:MyChildComponent model="{ model.myChildComponentPM }" ... />
...
</example:MyComponent/>

When a hierarchy of presentation models is established, coordination takes place by method calls between the PMs, sharing objects amongst them, and dispatching events up the hierarchy. So if a user selects an item from a DataGrid in View 2, a selectedItem property may be updated on PM 2 and an event dispatched to announce the selection. PM 1 may listen to this event and perform its own logic in response.

Componentized

With the componentized approach to the Presentation Model pattern, there is a single hierarchy of view components but no hierarchy of presentation models. Each view component has a corresponding presentation model, but these models are independent of one another, as shown in Figure 2.

PM3.png

Figure 2 - A hierarchy of components, each with a presentation model

With this approach, the PMs are usually injected into their corresponding views using the view-wiring mechanism of an IoC framework. For example, the following code could be used with Parsley 2:

<example:MyComponent ... 
   addedToStage="dispatchEvent(new Event('configureIOC', true'))">
<mx:Script>
[Inject] [Bindable] public var model:MyComponentPM;
</mx:Script>
<example:MyChildComponent/>
...
</example:MyComponent/>

Here the configureIOC event instructs Parsley to inject a presentation model instance, declared in a configuration file, into the model property of the view. Notice that there is no need to pass a model into the child component. Each component is self-contained and takes care of its own business.

A variation of this approach is to declare the presentation model directly in the view, as shown below:

<example:MyComponent ... >
<example:MyComponentPM id="model"/>
<MyChildComponent/>
...
</example:MyComponent/>

Although the presentation models are kept independent of one another with the componentized approach, there remains a need to coordinate the components in some way. This can best be achieved using an Inversion-of-Control (IoC) framework, such as Parsley, Swiz or Spring ActionScript. There are ways to do so:

  • Messaging - route messages directly between the models using whatever mechanism your preferred framework provides. Parsley 2 includes a loosely-coupled messaging framework; Swiz has a notion of mediated events; while Cairngorm MVC has a singleton event dispatcher that can serve a similar purpose.
  • Domain Interfaces - inject shared domain models into multiple PMs. Coordination then takes place when the PMs call methods on the interfaces to these models, and listen for events dispatched by them. All IoC frameworks support this feature.
  • Controller/Presenter - use separate classes, known as controllers or presenters, to coordinate multiple PMs. These classes are typically injected with a number of presentation models, using an IoC framework. The controllers then listen for events and invoke methods on the PMs.

The relative merits of these are not discussed here, but will be tackled in another article. Each approach achieves a similar result of de-coupling the components from one another. The two approaches to the Presentation Model pattern are now compared in terms of their responsiveness to change.

Responsiveness to Change

It is common for the visual designs of a user interface to change during development, based on user feedback, client demands, or moments of creative inspiration from the designers. In my experience, this usually happens when I've just put the finishing touches on the implementation, the pixels are perfectly aligned and the unit tests running green! So it's important to write code in such a way as to minimize the cost of change, allowing components to be manoeuvred from place to place and logic to be reused without great effort.

Consider the case where a view component needs to move from one region of the user interface to another. Starting with the simple hierarchy shown earlier in Figure 1, changes are required to four classes, now highlighted in red in Figure 3.

PM2.png

Figure 3 - Moving part of a View-and-PM hierarchy


View 3 needs to be detached from its starting place in View 1 and re-declared in View 2. Similarly, the reference to PM 3 contained in PM 1 needs be removed and introduced to PM 2. Any coordination logic that was in PM 1 also needs to be moved into PM 2.

In contrast, the componentized approach, first shown in Figure 2, responds more easily to change. Only the declaration of View 3 needs to be moved from View 1 to View 2, as highlighted in red in Figure 4.

PM4.png

Figure 4 - Moving a component within a hierarchy

Since the logic for the View-to-PM components is self-contained and coordination takes place externally, though messaging, domain interfaces, or controller/presenters, no further changes are necessary. If test-driven development is being practiced, the unit tests for the PMs also remain intact, whereas they would need to be refactored with the hierarchical approach.

Conclusion

The Presentation Model is a useful pattern for building testable Flex applications. By moving the state and logic used to present data and handle user gestures into PMs, it can be unit tested in isolation and understood more easily than Script-block logic placed directly within views. However, rich user interfaces can be somewhat volatile, changing their shape often during development, so it is recommended to apply a componentized version of the Presentation Model that is easy to adapt, rather than developing and ultimately maintaining a hierarchy of connected presentation models.

Posted by tsugden at August 24, 2009 9:32 PM

Comments

Thank you for putting together a clear comparison of the two approaches and demonstrating the advantages of the Componentized approach. Up until now I had seen both approaches used (sometimes together) and had been using the hiearchical approach just to be consistent but this entry makes me want to change my tune. -Sep 7 (incorrectly spammed and deleted, but recovered on Sep 29)

Posted by: diamondTearz at September 29, 2009 8:42 PM

Thanks for the comment. A componentized approach definitely helps to keep the focus on presentation concerns of a component, rather than creating and managing child PMs. However, it does require a nice mechanism for coordinating multiple components. An inversion-of-control container, like Parsley 2, really helps here. We sometimes create "presenters" or "controllers" for this purpose. They listen to events from PMs and update state on them too.

Posted by: Tom at September 29, 2009 8:51 PM

First of all, thanks for a great blogpost! It made me understand the difference between a componentized and hierarchical approach to PM.

However, there is one thing I'm still not sure about when it comes to applying PM's: What if you want to re-use a view, at two different places in an app. The view has just one PM right? And let's say this PM binds some input to a certain variable on a model.

What if you want the PM to use different instances of the model at different places in the app? What is the best way to implement this? Passing the model instance down from the views? This seems kind of messy...

Thanks!

Posted by: MKD at October 1, 2009 8:31 AM

That's a good question and you're right, some of the solutions are kind of messy...

1. Pass the PMs Down

This is workable, but pollutes the higher-level components. Passing down is less problematic at at the level of "reusable views". It's most troublesome if a large hierarchy is established, reaching across functional areas of the application. We tend to use this approach on our projects, except for the ones implemented with the Flicc framework. However, we plan to use approach 3 described below in the future.

2. Declare the PMs in the View

If you're declaring your PMs inside the view component and not using an inversion-of-control framework, you'll automatically have a new instance each time you reuse the view. If those PMs then need to access different instances of a model, you need a smart mechanism for looking up the right model instance. I can think of various ways to achive this, but the result does complicate the code, giving the component knowledge that it is "not the only one", so it may be preferable to pass down the PM instance.

3. Use View Definitions

If you're using the Parsley application framework, there is a nice solution coming in Parsley 2.2 called View Definitions. In your context file, you would declare 2 definitions like this:

<View id="myView1" type="{MyView}">
    <Property name="pm" idRef="myPm1"/>
</View>
<View id="myView2" type="{MyView}">
    <Property name="pm" idRef="myPm2"/>
</View>

When the views are added to the stage, Parsley will configure them, injecting different PMs into each. The definitions for the PMs themselves can be configured in whatever way you need.

See the Parsley roadmap for more details: http://www.spicefactory.org/parsley/docs/2.0/manual/roadmap.php#intro

Flicc is another lesser-known IoC framework that already supports this feature. It may be supported by Swiz, but I'm not sure?

4. Inject Non-Singletons By Type

Another approach when using an IoC framework would be to configure the PM to be a non-singleton, then to inject by type. Each instance of the view would end up with its own instance of the PM. You could use the same trick to get different instances of a child object into the PM. But again, you'd probably need to figure out a way to identify these instances in other parts of your code. You could do that by sending messages (a.k.a. broadcast events, mediated events, etc.) containing the instances.

---

I think Parsley is going to knock this one of the head with the new View Wiring mechanism included in 2.1 and the View Definition feature in 2.2. With 2.1, a child component can have its own context, with the messaging framework used to communicate with higher-level components. With 2.2, duplicate views can be configured differently as described in point 3 above.

I haven't been following Spring ActionScript or Swiz closely over the last couple of months, but I suspect they're considering the same issues and it'll be interesting to see how they solve them. Please correct me if they already have done.

Posted by: Tom at October 2, 2009 8:16 AM

Thanks for the answer! We are using Swiz, so I think it'll have to be solution #1 for us as well :)

Posted by: MKD at October 8, 2009 1:13 PM

Interested to hear about Domain model coordination in the componentized version in comparison to the other methods....

Posted by: Lyndon at January 25, 2010 1:29 AM

Post a comment




Remember Me?

(you may use HTML tags for style)