I have been using Robotlegs in my last few projects, and found it to be an excellent step on from my previous favourite; Pure MVC. I won’t go into the reasons why I like it so much, though there are many, but in general it feels far more flexible and requires less boilerplate than other solutions. However, no matter what framework you use, sooner or later you will hit a wall, needing to implement something can’t accommodate. I hit such a wall last week with the way Robotlegs wires up Mediators to their views.
Update: I have taken things a bit further along here.
I’ve been having an ongoing discussion with my good friend Simon about effective ways to implement views, and more recently, how to do so in Robotlegs. Obviously a Mediator is beneficial in keeping your view ignorant of your chosen framework, but where we’ve both been unsatisfied is in the organisation the view itself. I’m using view in the sense of a complex view as opposed to a simple component, or a more abstract notion of ‘The View’. It is perfectly possible to work on a very granular level and Mediate every single control in your application, but in my opinion this is painfully cumbersome, and results in your code being far too distributed and difficult to work with, especially if you are dealing with ongoing changes to UI. My preferred solution to this particular scenario is to break my application into views – logical collections of controls which might equate to a screen, or to a logically related chunk of functionality like a sidebar or a simple gallery. Of course all views are composite, and you could easily argue that even a simple control is a collection of other simpler controls which it has chosen not to expose directly, but for my purposes, I am talking about small collections of controls that are logically related.
By Mediating views on this level, I can be sure that a lot of the trivial inter-control communication can be kept out of my framework level communication, leaving the framework to deal with more important, abstracted notions of communication. In short, If I have a gallery view, the framework only needs to know when someone saves an image to their profile, not (necessarily) when a new image loaded or tagged. That kind of basic functionality can be kept in the view. Apart from anything else, I find it far easier to understand what is going on within a view because I don’t need to chase application flow out through the framework (except where necessary). It is also far easier to snap off chunks of functionality for development by separate individuals who need no knowledge of the framework or application as a whole.
Conversely, the problem with more complex views, is that there is more code in one place, and we have been looking for better ways to split this code down into logical pieces that are also practical to use when developing. The Mediator exists outside the edge of the view. It is a part of the view in the sense that it Mediates the view, but it is not a part of the view itself. Often when people talk about the Mediator, they compare it to a Presentation Model, but we both think that this is an incorrect comparison. A Mediator is there only to interpret communication from framework to view and view to framework. A Presentation Model is much more closely tied to its view. Here is Martin Fowler’s take:
Presentation Model pulls the state and behaviour of the view out into a model class that is part of the presentation.
and
Presentation Model may interact with several domain objects, but Presentation Model is not a GUI friendly facade to a specific domain object. Instead it is easier to consider Presentation Model as an abstract of the view that is not dependent on a specific GUI framework.
In short , it is not intended to to be framework dependant in the way that the Mediator is, and this is an important distinction. It is not an alternative to other presentation patterns but can compliment them.
What we wanted to avoid were mongrel MXML classes containing a nasty cocktail of MXML components, event handling, view logic, state and localised models, often in the form of a dataprovider or VO, or perhaps a series of disparate variables. Certainly this approach has its place. It makes sense for code examples, low fidelity prototypes and quick/dirty projects, but on longer or larger projects, it’s disadvantages outweigh its flexibility. What we wanted was to look at different ways of architecting our views, with the following constraints:
- The view should contain no framework specific code.
- The view should allow as much as possible of itself to be tested without any interaction testing.
- The view should be easy to work with and easy to understand; data flow should be clear and consistent.
- The view should offer a simple interface which hides its implementation from any framework that utilises it.
To solve this problem I have subclassed MediatorMap, modifying its API to allow another class reference to be passed in – an IInterceedingClass. When the mapped viewComponent is added to the stage, the Mediator is created as usual, but instead of the viewComponent being in injected into it, the viewComponent is injected into a new instance of the IInterceeding class which is itself then injected into the Mediator. This allows for many different types of view to be used with Robotlegs’ IMediators, not just a DisplayObject derived viewComponent. For example if an MVP triad was being used in the view, the Presenter could be mediated without the IMediator knowing about the viewComponent. Here is an example of the modified MediatorMap being used in an ApplicationContext:
//----------------------------------------------------------------------
// assemblerMap
//----------------------------------------------------------------------
protected function get interceedingMediatorMap() : IInterceededMediatorMap {
return super.mediatorMap as one.frameworks.robotlegs.extended.InterceededMediatorMap;
}
//----------------------------------------------------------------------------------
//
// Methods
//
//----------------------------------------------------------------------------------
public function ApplicationContext() {
super();
// Create our alternative implementation of IMediatorMap which
// subclasses MediatorMap
_mediatorMap = new InterceededMediatorMap(contextView, injector, reflector);
}
/**
* @inheritDoc
*/
override public function startup() : void {
//Controller
commandMap.mapEvent(ColourSelectionEvent.SELCTION, UpdateModelCommand);
//Model
injector.mapSingletonOf(IDataModel,DataModel);
//Login View Injection Points
injector.mapClass(ViewModel, ViewModel);
injector.mapClass(ViewData, ViewData);
//Interceeded Mediators
interceedingMediatorMap.mapInterceededView(app.view.components.MVP.View, MVPMediator, Presenter);
interceedingMediatorMap.mapInterceededView(app.view.components.viewHelper.View, ViewHelperMediator, ViewHelper);
//Standard Mediators
interceedingMediatorMap.mapView(app.view.components.autonomousView.View, AutonomousViewMediator);
super.startup();
}
In later posts I will talk about different approaches to organising complex views and how best to wire them into Robotlegs. Also keep an eye on www.newtriks.com for related posts and Chandima’s forthcoming series on Presentation Patterns.
Browse Timeline
Comments ( 3 )
[...] my previous post, I modified Robotlegs’ MediatorMap to allow classes that were part of the view, but not [...]
1ndivisible » Making Robotlegs’ Mediation of Views More Flexible Part II added these pithy words on Mar 03 10 at 10:28 pmThanks for this thoughtful article. Have you done any work on the performance hit of this approach? Clearly since it is for high-level architecture that’s not a big deal, I am just curious.
Hey Alec,
What kind of performance are we talking about? Compared to RL’s standard Mediator map, it is trivial – an extra class instantiated when your viewComponent is added to the stage. In terms of application flow through more classes, I think it is high level enough for it not to be an issue.
I’ve just made some modifications to allow for factories to be passed in. There is no longer the assumption that your interceeding class knows about the view (For example in the Presentation Model it is the other way round) so you can wire up your view classes however you like. I’ll post them tomorrow if I get the chance.
