Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

A robotlegs context that enables mediators to map to interfaces without mentioning any concrete classes at all

branch: master
readme.textile

View Interface Mediator Map

A pure view interface enabled MediatorMap for use in a Robotlegs context

Rationale

When using Robotlegs you sometimes you want to inject a view into a mediator as an interface. For example

public class MyViewMediator extends Mediator
{
	[Inject]
	public var view:IMyView;
}

The normal mechanism for mapping this in your context is to add a third argument to the mapView command telling the mediatorMap what you would like to inject the view ‘as’

override public function startup():void
{
	mediatorMap.mapView(MyViewClass,MyViewMediator,IMyView);
}  

The problem with this is that it adds a concrete reference to a concrete class in the context – MyViewClass. It would be nice to simply specify the view interface and mediator.

Enter the ViewInterfaceMediatorMap. It is a drop in replacement for the current 1.3.0 Robotlegs MediatorMap with all of the same functionality, but with the added bonus that you can map mediators directly to view interfaces. The above piece of code could then be written

override public function startup():void
{
	mediatorMap.mapView(IMyView,MyViewMediator);
}

This has a number of advantages:

  • Your context only cares about what your view does not how it does it.
  • A context swc can be produced that has no dependencies on actual view implementations.
  • The concrete view classes do not have to be baked in at compile time. You can swap views in and out at runtime, even from loaded modules, and as long as they implement the interface, the correct mediator will be created for them even though the context will never have seen the actual concrete classes before.

Usage

In order to use this new mediator map simply extend the Robotlegs Context as normal and override the get mediatorMap property like so

public class MyContext extends Context
{
    //
    // Override the default mediator map with one that can map to interfaces
    //
    override protected function get mediatorMap():IMediatorMap
    {
        return _mediatorMap ||= new ViewInterfaceMediatorMap(contextView, createChildInjector(), reflector);
    }
}

With this done you can map mediators to view interfaces.

Performance

Mapping mediators to views is the least performant bit of Robotlegs. Adding the concrete class to the mapView call allows it to be faster. However this mediator map has been benchmarked with the software here and it has been found to be only fractionally slower than the normal mediator map.

Signals

This extension really benefits from the use of as3-signals since they enable a view to impement an interface, something that simply does not fit into the way events work. Please see the example.

Example

In the repository is a very simple example that shows how mapping to an interface can enable multiple view mechanisms and components to ‘plug in’ to the same underlying business logic.

The example is written as if it were a big application and so it is massively over engineered. The code is however intended to show a very clean approach to application and component development. It is like the application and views that control it are two separate things – which is good.

The application consists of a simple context

package example.mvcs
{
    public class InterfaceEnabledMediatorMapContextExample extends Context
    {
        override protected function get mediatorMap():IMediatorMap
        {
            return _mediatorMap ||= new ViewInterfaceMediatorMap(contextView, createChildInjector(), reflector);
        }
        override public function startup():void
        {
            injector.mapSingleton(NumberModel);
            injector.mapSingleton(NumberUpdatedSignal);
            mediatorMap.mapView(INumberEntry,NumberEntryMediator);
            mediatorMap.mapView(INumberDisplay,NumberDisplayMediator);
            commandMap.mapEvent(NumberEnteredEvent.NUMBER_ENTERED,NumberEnteredCommand);
        }
    }
}

Where we can see that two mediators are mapped to two different interfaces. The interfaces use signals to represent the transmission of information between the application and its view, for example the INumberEntry interface looks like this

package example.view
{
    import org.osflash.signals.ISignal;
    public interface INumberEntry
    {
        function get numberEntered():ISignal;
    }
}

If a view that implements this interface is added to the stage then a NumberEntryMediator is created for it which should understand the signal that it dispatches. When a number is chosen by the view it dispatches a signal to show that the selected number has changed, this causes a command to be triggered inside the application (NumberEnteredCommand) that updates a model which updates the view.

The application actually has three views that implement the INumberEntry interface and which one is currently in use can be chosen by a dropdownlist. Even though there is only one mapping in the context, and the context has never seen these classes the application still works and each input mechanism works as it should.

Something went wrong with that request. Please try again.