Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: State Machine and ViewState example - Flex 3.4  (Read 11360 times)
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« on: December 14, 2009, 02:23:29 »

Hello,

I just started playing around with the FSM StateMachine utility and in my process of getting a grasp on how it works through viewing other examples, I created my own example which utilizes 1 button to cycle through states with 1 Action message.  I've also setup the app to use a flex ViewState in conjunction with the FSM.  The purpose here is separate out the different parts of the application as loosly as possible.  In my comments you will find some ideas on a more complex proxy than the initial included proxy.  Also in the Injector command I explain in more detail a concept for state cycling via 1 action command. 

The methods here behind my madness are to keep the view as uncoupled as possible - specifically the mxml file(s).  Personally, I like to avoid actionscript in the mxml file and directly binding functions in the event attributes.  I'd rather register listeners in the mediator and handle as much of it as possible there.  So other than the Facade setup, and 1 dispatcher function (left there for simplicity), the rest of the AS code is in AS files.

If anyone has an example of a better or even different way of tying the FSM to ViewStates, I'd love to see them and I am completely open to suggestions. 

This simple example is a result of me examining the StopWatch example and then building from the ground up based on the concepts found within the StopWatch project.  So it should be fairly familiar in general for much of the core.

Enjoy and I look forward to any comments/responses.

TJ
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: December 15, 2009, 09:00:09 »

Personally, I like to avoid actionscript in the mxml file and directly binding functions in the event attributes.  I'd rather register listeners in the mediator and handle as much of it as possible there.

This is how I started out with Flex back in the 1.0 days. It seemed clean. I was using Cairngorm and used the ViewHelpers as this 'code-behind' that I put the smarts into. And there was a good reason for keeping code out of the components - you couldn't ASDoc them. (you can now though).

But over the years I realized this is not good. You cannot write a portable view component this way. The component needs to encapsulate it's own behavior. If you put the logic for your view component into your Mediator you are actually binding yourself very tightly to the PureMVC framework.

Realize that while it looks like a mere markup language like HTML, MXML IS ActionScript. It compiles down to ActionScript code. So when you create a custom component, adding a script block to it isn't a bad practice. It is a best practice. When you start doing code-behind in the Mediator, you inevitably end up exposing more knowledge about the internals of the component than necessary because there is no code in your component, and the Mediator has to poke everything into the various subcomponents for display. This breaks the encapsulation of the component; one of the biggest no-nos you can make in OOP.

Consider the way you would adapt a third party mapping component to your PureMVC app. It would expose some API of methods and properties for you to feed it data and it would emit certain events that you can respond to. But likely you would not get to micromanage the internals of the component, nor would you expect to. And it would be extremely unlikely that the component would come with a Mediator and instructions to register it in your PureMVC app either. That would be silly from a component developer perspective, since it would narrow the potential market for the component down to PureMVC users. So why would you develop and manage your own components any differently than you would a third party component?

-=Cliff>
Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #2 on: December 15, 2009, 09:41:25 »

I see your point, but I'm not sure how one could implement a relationship between a mediator and a view without some form of tight coupling.

Example:  You have a view with various components (buttons, lists, etc) and you define the event handlers for those components in the script block to send custom event messages, etc.  This is all fine and dandy, but there are still to hurdles I see that prevent a loosely coupled design:

1 - Bridging between the Events on the display and messages in the facade.  One would still have to register an event listener for the view within the mediator for events dispatched by the view (user clicks and what not)...

2 - Pushing dataproviders into the view.  Say a collection of items from a proxy for a list control. Proxy.SUCCESS message to mediator (or command and then to mediator depending on design).  However, once you are at the mediator, you still need to access the list in the view through an implicet getter or similar to access the list and pass it the data collection.

So Cliff, (or anyone else for that matter) please set me straight if I have completely missed something here.  I carry no degrees or education in computer science. I'm self taught and my desire is to write solid and maintainable code.  Therefore, is there a way to truely separate out the coupling completely or is there an acceptable level or coupling contamination between the view and the mediator that I should not be concerned with? I believe I am in need of a little schooling...

I am merely 'Grasshopper', but one day I hope to 'snatch the pebble' from your hand...  ;D
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: December 15, 2009, 02:02:32 »

I see your point, but I'm not sure how one could implement a relationship between a mediator and a view without some form of tight coupling.

It will be a coupling. From the Mediator to the Component. Your Mediator will listen to events from the component and will call methods or set properties on it. There should however be no coupling from the component to the Mediator; i.e. shouldn't know anything about the Mediator.

The tightness of the coupling has everything to do about how well you encapsulate your component. The Mediator shouldn't be a puppeteer, knowing and controlling everything that goes on inside the component.

It shouldn't know, for instance that you're using a data grid instead of a combo box to display the data delivered to the component. Therefore it shouldn't reference component.searchResultsGrid.dataProvider to set the data. Instead it should set a bindable property on the component with a semantic name like searchResults. Inside the component, the data grid would bind its dataProvider to the searchResults property. This leaves you free to change the component's implementation (to say a combo box instead of a data grid) without needing to also change the Mediator.

By the same token, the Mediator shouldn't be setting listeners on the sub-components of its view component. This is where the component typically needs to have a modicum of intelligence to encapsulate its own behavior. For instance, say that selecting an item in the data grid should enable some buttons, resize the grid and display a form alongside it for editing.

The Mediator doesn't need to play a part in this. A local handler in the data grid should trigger some code that resizes everything and enables the buttons. This code might be all done with binding expressions which is still code, just written in the handler of the MXML tag instead of a script block. Or it might be that the click handler on the grid triggers a local method that does the rearranging of things, and sets a bindable variable to the selected item cast to its appropriate type. And this property is what the Mediator should inspect if it gets an event saying the data needs to be shipped off to the server (say when the now enabled submit button is pressed).

-=Cliff>
« Last Edit: December 16, 2009, 10:31:30 by puremvc » Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #4 on: December 16, 2009, 10:21:09 »

Hey Cliff,

Thanks so much for taking the time to explain that in more detail. You just created extra work for me LOL!  Good thing is I got it approved through my boss. They know I strive to write good code and allow me freedoms for improvement and education during a development process. 

I broke off to a branch of the current project I am working on and I am in the process of rewiring according to your advice.  My mediator has fallen victim to being a puppetier and I want to fix that.

The project is a media library administration app for a company website.  The admin is able to FTP flv, wmv, mp3, images, pdfs, etc., to the site's library and entries are logged to corresponding tables in a database.  I just began a couple of days ago, so I'm not to far and it's a good time to rework. 

I'll post an update with any relevant issues in the code here for feedback or solutions to help others as I they become available.

Thanks again for your time in posting your response.

In the mean time, if anything else helpful comes to mind, please post and I will read it immediately.
Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #5 on: December 16, 2009, 03:15:30 »

Update:

It makes even more sense now as to why one should leave the viewState for the view and the FSM is for the logic/Facade. I am working on a project in Flash Builder Beta 2, and the new syntax for the viewstate makes everything easy to manage within the view (and obvious as to what it's doing). So now I understand more clearly the implementation, thus keeping the view and mediator as independent as possible.

 Here is some view mxml utilizing the new viewState syntax:
:
<s:HGroup gap="5" width="100%">
<mx:ComboBox id="category" width="430" labelField="NAME_VCC"
enabled.BASE="false" enabled.INIT="false"
dataProvider="{dpCategories}" selectedIndex.BASE="-1" />
<s:Button id="btnUpload" label="Upload Movie" width="100%" label.EDIT="Update Selection"
  enabled="false" enabled.INIT="false" enabled.BASE="false"
  click="uploadRequestHandler(event);" />
<s:Button id="btnCancel" label="Cancel" width="100%" click="btnCancelHandler(event);"
  enabled.BASE="false" enabled.INIT="false"/>
</s:HGroup>

My viewStates:
:
<s:states>
<s:State id="stInit" name="INIT" />
<s:State id="stBase" name="BASE" />
<s:State id="stUpload" name="UPLOAD"/>
<s:State id="stEdit" name="EDIT"/>
</s:states>


Actions and states for the FSM:
:
// actions for the state machine
public static const ACTION_GOTO_EDIT_STATE:String = '/action/goToEditState';
public static const ACTION_GOTO_UPLOAD_STATE:String = '/action/goToUploadState';
public static const ACTION_BROWSE_FOR_FILE:String = '/action/browseForFile';
public static const ACTION_SELECT_FILE:String = '/action/selectFile';
public static const ACTION_CANCEL_SELECT_FILE:String = '/action/cancelSelectFile';
public static const ACTION_CHECK_FLV_EXISTS:String = '/action/checkFlvExists';
public static const ACTION_FTP_UPLOAD_FLV:String = '/action/ftpUploadFlv';

// states for the state machine
public static const STATE_IDLE:String = '/state/idle';
public static const STATE_UPLOAD:String = '/state/upload';
public static const STATE_EDIT:String = '/state/edit';
public static const STATE_FILE_REF_OPEN:String = '/state/fileRefOpen';
public static const STATE_FILE_EXISTS_CHECK:String = '/state/fileExistsCheck';
public static const STATE_FTP_TRANSFER:String = '/state/ftpTransfer';

And lastly, the only vars in the view which my mediator is aware of:
:
[Bindable]
public var dpFlvList:ArrayCollection;
[Bindable]
public var dpCategories:Object;
[Bindable]
public var flvDataObject:Object;

I now have alot less code overall, and my mediator is much smaller than before. 

So now I see my error of the original example I posted in which I was using the FSM/Facade to control the viewstate through the Mediator - Bad idea.

Logged
Pages: [1]
Print