immerzeel
|
|
« Reply #4 on: October 17, 2007, 03:03:03 » |
|
About mediators without a view. I have got one and it was kind of difficult for me to see where the code should be. First I decided to make it a Proxy, but it has to send and receive Notifications, which doesn't apply to the model (AFIAK).
This is an implementation of SWFAddress, which allows deeplinking in the SWF. It changes the URL, which allows bookmarking. On view changes I send a Nofication from my ApplicationMediator, which this class receives and changes the URL. When someone lands on the site with an URL, this class sends a similar Notification to change the view in the ApplicationMediator. The internalUpdate switch prevents the application from looping.
I tried to implement it in the ApplicationMediator, but that got too messy and bloated for my taste.
My questions are: Should it be a Proxy? if so, what to do about the Notification handling? Should it stay a Mediator? The BrowserMediator gets fed a null object in the ViewPrepCommand, which smells a bit funny. Should it be a stand-alone class? My problem then is where do I put it, this was the simplest solution I could think of. Are the (public) constants and 'switch' statements bad practice? I do prefer 'switch' over 'for', it is easier to read.
package com.ip.nowhere.view { import org.puremvc.patterns.mediator.Mediator; import org.puremvc.interfaces.IMediator; import org.puremvc.interfaces.INotification; import com.ip.nowhere.ApplicationFacade;
/** */ public class BrowserMediator extends Mediator implements IMediator { /** * Canonical name of <code>BrowserMediator</code>. */ public static const NAME : String = "BrowserMediator"; public static const EVENTS : String = "/events"; public static const WORKSHOPS : String = "/workshops"; public static const SEARCH : String = "/search"; public static const NEWS : String = "/news"; public static const AGENDA : String = "/agenda"; public static const PICS : String = "/pics"; public static const FILM : String = "/film"; public static const SPEAK : String = "/speak"; public static const READ : String = "/read"; public static const ART : String = "/art"; public static const SHOW : String = "/show"; /** * View is internally updated. * If true, <code>handleSWFAddressChange</code> won't send the * notfications. */ private var internalUpdate : Boolean = false;
/** * Constructor. * * @param viewComponent */ public function BrowserMediator(viewComponent : Object) { super(viewComponent); SWFAddress.onChange = handleSWFAddressChange; }
/** * Get <code>BrowserMediator</code> name. * * @return Name of <code>BrowserMediator</code>. */ override public function getMediatorName() : String { return BrowserMediator.NAME; } /** * List all notifications. * * @return Array List of Notification names. */ override public function listNotificationInterests() : Array { return [ApplicationFacade.STARTUP, ApplicationFacade.VIEW_EVENTS, ApplicationFacade.VIEW_WORKSHOPS, ApplicationFacade.VIEW_SEARCH, ApplicationFacade.VIEW_NEWS, ApplicationFacade.VIEW_AGENDA, ApplicationFacade.VIEW_PICS, ApplicationFacade.VIEW_FILM, ApplicationFacade.VIEW_SPEAK, ApplicationFacade.VIEW_READ, ApplicationFacade.VIEW_ART, ApplicationFacade.VIEW_SHOW]; } /** * Handle all Notifications. * * @param note Notification. */ override public function handleNotification(note : INotification) : void { internalUpdate = true; switch(note.getName()) { case ApplicationFacade.STARTUP: case ApplicationFacade.VIEW_EVENTS: SWFAddress.setValue(EVENTS); break; case ApplicationFacade.VIEW_WORKSHOPS: SWFAddress.setValue(WORKSHOPS); break; case ApplicationFacade.VIEW_SEARCH: SWFAddress.setValue(SEARCH); break; case ApplicationFacade.VIEW_NEWS: SWFAddress.setValue(NEWS); break; case ApplicationFacade.VIEW_AGENDA: SWFAddress.setValue(AGENDA); break; case ApplicationFacade.VIEW_PICS: SWFAddress.setValue(PICS); break; case ApplicationFacade.VIEW_FILM: SWFAddress.setValue(FILM); break; case ApplicationFacade.VIEW_SPEAK: SWFAddress.setValue(SPEAK); break; case ApplicationFacade.VIEW_READ: SWFAddress.setValue(READ); break; case ApplicationFacade.VIEW_ART: SWFAddress.setValue(ART); break; case ApplicationFacade.VIEW_SHOW: SWFAddress.setValue(SHOW); break; default: } } /** * Handles the <code>onChange</code> event of <code>SWFAddress</code>. */ private function handleSWFAddressChange() : void { if (!internalUpdate) { switch(SWFAddress.getValue()) { case EVENTS: sendNotification(ApplicationFacade.VIEW_EVENTS); break; case WORKSHOPS: sendNotification(ApplicationFacade.VIEW_WORKSHOPS); break; case SEARCH: sendNotification(ApplicationFacade.VIEW_SEARCH); break; case NEWS: sendNotification(ApplicationFacade.VIEW_NEWS); break; case AGENDA: sendNotification(ApplicationFacade.VIEW_AGENDA); break; case PICS: sendNotification(ApplicationFacade.VIEW_PICS); break; case FILM: sendNotification(ApplicationFacade.VIEW_FILM); break; case SPEAK: sendNotification(ApplicationFacade.VIEW_SPEAK); break; case READ: sendNotification(ApplicationFacade.VIEW_READ); break; case ART: sendNotification(ApplicationFacade.VIEW_ART); break; case SHOW: sendNotification(ApplicationFacade.VIEW_SHOW); break; default: } } SWFAddress.setTitle(ApplicationProxy.getTitle() + SWFAddress.getValue()); internalUpdate = false; } } } Next is the ApplicationMediator class. The registerChild method registers the views that act like screens. The selectedChild method makes the selected view visible and hides the others (this is my semi-implementation of Flex's ViewStack, as this is an AS3/Flash application). As you can see both classes seem similar and don't feel DRY. It works, but I am open to refactoring and complying to best practices .
Later,
Pascal
package com.ip.nowhere.view { import flash.display.MovieClip; import org.puremvc.interfaces.IMediator; import org.puremvc.interfaces.INotification; import org.puremvc.patterns.mediator.Mediator; import com.ip.nowhere.model.ApplicationProxy; import com.ip.nowhere.ApplicationFacade;
/** */ public class ApplicationMediator extends Mediator implements IMediator { /** * Canonical name of <code>ApplicationMediator</code>. */ public static const NAME : String = "ApplicationMediator"; private var applicationProxy : ApplicationProxy; /** * Constructor. * * @param viewComponent */ public function ApplicationMediator(viewComponent : Object) { super(viewComponent); applicationProxy = facade.retrieveProxy(ApplicationProxy.NAME) as ApplicationProxy; applicationProxy.registerChild(ApplicationFacade.VIEW_EVENTS, application.eventsView); applicationProxy.registerChild(ApplicationFacade.VIEW_WORKSHOPS, application.workshopsView); applicationProxy.registerChild(ApplicationFacade.VIEW_SEARCH, application.searchView); applicationProxy.registerChild(ApplicationFacade.VIEW_NEWS, application.newsView); applicationProxy.registerChild(ApplicationFacade.VIEW_AGENDA, application.agendaView); applicationProxy.registerChild(ApplicationFacade.VIEW_PICS, application.picsView); applicationProxy.registerChild(ApplicationFacade.VIEW_FILM, application.filmView); applicationProxy.registerChild(ApplicationFacade.VIEW_SPEAK, application.speakView); applicationProxy.registerChild(ApplicationFacade.VIEW_READ, application.readView); applicationProxy.registerChild(ApplicationFacade.VIEW_ART, application.artView); applicationProxy.registerChild(ApplicationFacade.VIEW_SHOW, application.showView); } /** * Get <code>ApplicationMediator</code> name. * * @return Name of <code>ApplicationMediator</code>. */ override public function getMediatorName() : String { return ApplicationMediator.NAME; } /** * List all notifications. * * @return Array List of Notification names. */ override public function listNotificationInterests() : Array { return [ApplicationFacade.STARTUP, ApplicationFacade.VIEW_EVENTS, ApplicationFacade.VIEW_WORKSHOPS, ApplicationFacade.VIEW_SEARCH, ApplicationFacade.VIEW_NEWS, ApplicationFacade.VIEW_AGENDA, ApplicationFacade.VIEW_PICS, ApplicationFacade.VIEW_FILM, ApplicationFacade.VIEW_SPEAK, ApplicationFacade.VIEW_READ, ApplicationFacade.VIEW_ART, ApplicationFacade.VIEW_SHOW]; } /** * Handle all Notifications. * * @param note Notification. */ override public function handleNotification(note : INotification) : void { switch(note.getName()) { case ApplicationFacade.STARTUP: case ApplicationFacade.VIEW_EVENTS: applicationProxy.selectedChild = ApplicationFacade.VIEW_EVENTS; break;
case ApplicationFacade.VIEW_WORKSHOPS: applicationProxy.selectedChild = ApplicationFacade.VIEW_WORKSHOPS; break;
case ApplicationFacade.VIEW_SEARCH: applicationProxy.selectedChild = ApplicationFacade.VIEW_SEARCH; break;
case ApplicationFacade.VIEW_NEWS: applicationProxy.selectedChild = ApplicationFacade.VIEW_NEWS; break;
case ApplicationFacade.VIEW_AGENDA: applicationProxy.selectedChild = ApplicationFacade.VIEW_AGENDA; break;
case ApplicationFacade.VIEW_PICS: applicationProxy.selectedChild = ApplicationFacade.VIEW_PICS; break;
case ApplicationFacade.VIEW_FILM: applicationProxy.selectedChild = ApplicationFacade.VIEW_FILM; break;
case ApplicationFacade.VIEW_SPEAK: applicationProxy.selectedChild = ApplicationFacade.VIEW_SPEAK; break;
case ApplicationFacade.VIEW_READ: applicationProxy.selectedChild = ApplicationFacade.VIEW_READ; break;
case ApplicationFacade.VIEW_ART: applicationProxy.selectedChild = ApplicationFacade.VIEW_ART; break;
case ApplicationFacade.VIEW_SHOW: applicationProxy.selectedChild = ApplicationFacade.VIEW_SHOW; break;
default: } } /** * Cast the <code>viewComponent</code> to its actual type. * * @return viewComponent */ protected function get application() : MovieClip { return viewComponent as MovieClip; } } }
|