So I am on the quest to create a hybrid MVC mini-framework that combines some of the best elements of Cairngorm, PureMVC and Maté. The idea is to use the Command pattern from Cairngorm (because I like all my service/UX logic to be placed there and the EventMap’s dependencies on binding and MXML seem limiting), the Mediator pattern from PureMVC (which unclutters and decouples the views) and the EventMap and Injection logic from Maté (which will help to further decouple some of the command=>model logic).
Keep in mind I have only really been working with Maté for a couple of months and have only dived into actually understanding it in the last week or so. So if you know of a better way of doing what I am trying to accomplish, please let me know and I can update the article.
This will mostly address how to decouple some of that command => model logic. This means we are striving to get the command classes as model-agnostic as possible. It also means there needs to be a slight modification to the current CairngormCommand structure. We will keep the CairngormEvent in use because its data payload is useful in sending data back and forth from the event dispatchers/listeners. In order for a command to send info back to a listener, it will need to extend EventDispatcher. Then depending on the result or fault logic, it can dispatch an appropriate event with a data payload. Here is some stub code:
public class SampleMateFriendlyCommand extends EventDispatcher implements IResponder { public function execute (evt:Event):void { //the function signature could be anything including execute (... args) //notice I am not implementing the ICommand interface as I want to have more flexibility } public function result (data:Object):void { //parse data object if needed. var evt:CairngormEvent = new CairngormEvent("success"); evt.data = parsedResultDataObject; dispatchEvent(evt); } public function fault (info:Object):void { //parse info object if needed. var evt:CairngormEvent = new CairngormEvent("fault"); evt.data = parsedFaultInfoObject; dispatchEvent(evt); } }
I like the Command pattern because I think of it in a military sense. You issue a command to a soldier and that soldier executes the command, then generally reports back. So this is akin to that analogy. Next we need to see how to get the data back to the EventMap in order to wire the result/fault data into the appropriate places. I tinkered with this for quite some time before stumbling upon this solution. The Maté API docs are decent but fail to cover much beyond explaining the self explanatory. I really hope they work on their API docs and really flesh out the information.
<mate:EventHandlers id="applicationCompleteHandler" type="{AppEvent.SAMPLE_MATE_COMMAND}" debug="true"> <mate:AsyncCommandInvoker generator="{SampleMateFriendlyCommand}" successType="result"> <mate:successHandlers> <mate:PropertySetter generator="{SomeModelObject}" targetKey="data" source="{scope.currentEvent.data}"/> </mate:successHandlers> </mate:AsyncCommandInvoker> </mate:EventHandlers>
The AsyncCommandInvoker allows you to specify the event type that will trigger the successHandlers or the faultHandlers. Accessing the data payload for the result or success event is done using scope.currentEvent.data. Again I must reiterate that I stumbled upon this find because there was no documentation that I could find to support what I was trying to do.
The cool thing about this is that you have now freed up your commands so that they needn’t know about any specific model objects. That is unless you really want to strongly type your result data objects. This freedom allows for better testing as you can simply wire up a testing event map if you want to unit test.
Next up will be trying to wire mediators and their respective views into the event map.