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: Mediator notification handling  (Read 16666 times)
graphex
Newbie
*
Posts: 6


View Profile Email
« on: July 07, 2007, 01:26:25 »

So, I'm just getting in to PureMVC and one thing that struck me as being odd was the way notifications are subscribed and handled. I'm not a big fan of handling program flow with a big case statement - to me it wreaks of procedural programming and begs for refactoring to improve reusability and maintainability (without hurting readability).

I know that in IIBP, Cliff talks about how it seems more readable to differentiate events from notifications by the fact that notification handlers are in this big case statement in handleNotification, but that sounds to me like the architectural choice is being affected too much by the event implementation inside Flash/Flex. It could be just as easy and readable to handle events from the viewComponent with "onEventName" and to handle notifications with "handleNotificationName".

The other aspect about this construct that troubles me is that in your subscriber (the Mediator implementation) you're handling the actual subscription and implementation of its handler separately such that it is not noticeable at compile time. For instance, you can easily subscribe to ApplicationFacade.SEARCH_FAILED without implementing a means to handle that subscription, potentially leading to unnecessary subscriptions down the road, and generally making it harder to maintain.

What is the logic behind not providing a reference to the implementation method during the subscription? That way if the implementation is removed, the subscription will be invalidated in a way detectable at compile time. It also seems like handling different notifications through different methods allows those methods to be more easily reused down the road.

I think another major reason to avoid the single notification handler with the big switch statement is that it tempts the developer to add pre- and post-handling code in handleNotification. Doing things that way would seriously bind any notification handling logic to that one component, and make that component's implementation very rigid. For example if you had 99 cases in a switch statement that were happy with the preprocessing that occurred before the switch statement, and 1 notification handler that wasn't, you're basically setting yourself up for 99 refactorings or one poorly chosen 'if' statement.

If I do go with PureMVC, I'll probably end up subclassing Mediator to obfuscate listNotificationInterests and handleNotification in favor of a more event-type dispatcher within the mediator class. It isn't good to have event dispatching going on within each mediator, but I'm not sure what other components would need to be changed to do it the right way.

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



View Profile WWW Email
« Reply #1 on: July 07, 2007, 03:53:44 »

Sean,

Mediators should play a fairly simple and mechanical role in the architecture:

  • Receive Event information from their View Components, gather information from the View Component and/or custom Event and send it off in a Notification.
  • Receive Notifications, extract the data mostly from the Notification, and update the View Component.

Similar to a switchboard operator. Who are you calling, sir? Ok, I'll route you through.

Although you can do most anything in a Mediator, limiting it to this role and pushing more complicated stuff, (the sort of stuff you might actually want to reuse) into a Command is a better idea. This keeps the Mediator simple and lightweight, doing only the minimum work necessary to adapt the View Component to the system.

For guidance about the Mediator's role, examine the three Mediators of the Architecture 101 demo, and how they adhere to this simple ambition. Note that a more complicated activity such as deleting a User (and their associated Roles) are done in a Command.

Because they are special case adapters for custom View Components, it is not expected that Mediators will be the most reusable aspect of a system. Due to the relatively simple role Mediators play, I sought the simplest way of 'plugging' them into the system.

But of course this doesn't change the way you feel about the particular implementation. This is why I did my best to make PureMVC a system where you could take or leave as much as you want. If you're down with the out of box way of doing things, great. If not, there are plenty of ways to customize it to your like.

So as to how you might override this Mediator Notification behavior:

When the the View class's registerMediator method is called, it interrogates the Mediator for a list of Notification interests, by calling its listNotificationInterests method. The View maps each Notification name returned to an Observer object that points the Mediator instance and a predetermined callback method - handleNotification.

Examine the View.registerMediator method to see how this happens.

Inside View.registerMediator, when an Observer object is created, it is registered with the View's Observer Map through a call to the public method registerObserver. We typically don't create Observers, they're usually used internally by the Core actors to map Commands and Mediators to Notifications.

Consequently, the Facade does not have a registerObserver method, and it is not required by IFacade, which exposes the Core actor methods that are expected to be in typical use, and not actually the full IView, IModel and IController interfaces.

Your first step is to simply not return anything from listNotificationInterests in your Mediator. This way the View simply registers the Mediator in its Mediator Map and goes on about its business.

Then you want to add a registerObserver method to your concrete ApplicationFacade. This method should in turn call registerObserver on the View. It is not governed by an interface, so its signature can be different from that of the View. This means it can save the Mediator the work of constructing the Observer object, as sendNotification does for INotifiers.

Have your registerObserver method accept the Notification name, a reference to the Mediator instance, and a reference to the callback function. Then it would construct an appropriate Observer instance and call view.registerObserver. (the Facade has a local protected reference to the View Singleton called 'view')

Next, in your Mediator constructor, for each Notification you want to be notified of, do this:

facade.registerObserver( ApplicationFacade.SOME_NOTIFICATION_NAME, this, handleSomeNotification );

That should get you where you're wanting to go.

If I get a chance I'll work this into the courseware. I'm coming up on the section about Mediators, and clarifying this subject with hands on examples would probably be good. This is one of those areas, where the out of box way is simple and will cover most cases, but if you want a different flavor of behavior, you can get to it quickly.

Thanks for bringing this up.
Logged
graphex
Newbie
*
Posts: 6


View Profile Email
« Reply #2 on: July 07, 2007, 06:09:14 »

Maybe I was envisioning too much implementation in the Mediator. Nevertheless, I don't like using switch statements for that purpose, so I'll see what I can do with a subclass. Of course, this being my first PureMVC project, I'm hesitant to do too much before I have a really good grasp of the framework.

I'll post what I end up doing to overcome my switch statement allergy.
Logged
drp2179
Courseware Beta
Newbie
***
Posts: 1


View Profile Email
« Reply #3 on: August 23, 2007, 12:36:22 »

I have to concur with Sean.  The use of a switch statement to de-mux the mediator notifications takes me back to my early Windows programming days - and not in a good way.  I agree that a mediator should be a "get in, get out" type of object, but the case statement has a "smell" to it for me.  If you can have a hardcoded callback (handleNotification), you can have a customized callback.  Internally, I think it requires one additional level of indirection more than what's there now.  From an API perspective I'd prefer to see a registerNotificationInterest( noteName, callbackMethod) type method.

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



View Profile WWW Email
« Reply #4 on: August 23, 2007, 04:42:09 »

I've stated above as clearly as possible the reasoning for the use of switch  inside handleNotification. I also realize that some people have a predisposition about the use of the switch keyword. If it were truly that vile, I doubt it would still live in so many OOP languages, AS3 included. That is an issue/witchhunt to take up with ECMA and Adobe, I suppose. As with all things, it has its place. A SIMPLE place.

As for why the implementation is the way it is; because I wanted a SIMPLE way of hooking these Mediators up. I didn't want all the extra lines of code necessary to explicitly subscribe, nor did I want to have to write lots of separate methods, when the role of the Mediator in responding is necessarily SIMPLE. If you find yourself with lots of stuff to be done in response to a given Notification in a Mediator, then you are looking at a clear symptom of responsibility misplacement.

Why? Think about what you might be doing in a Mediator in response to a Notification.

  • Sending more notifications. Simple.
  • Setting/getting properties on the View Component. If this isn't simple, then the API you're exposing in the View Component isn't 'BlackBoxy' enough. Though the Mediator has a somewhat intimate relationship with the View Component, the View Component still needs to encapsulate its implementation.
  • Setting some data on a Proxy. Simple, but if not (i.e. transforming it first or updating lots of Proxies in a transactional manner), probably should be handed to a Command. Business logic belongs in Commands.
  • Fetching some data from one or more Proxies. Simple, but if not,(i.e massaging it 20 ways to Sunday first), then it that probably goes in a Command, OR the Proxy itself. (In a Command if the massaging is specific to this View implementation, in the Proxy if it is a transformation you might perform again in a different application that uses the same Model and Proxies.)

So, again the action happening inside the cases of that switch statement in the handleNotification should be dirt simple. They shouldn't require any pre/post processing, and I've never advocated such, though I'll be sure to ward people away from it in the next rev of the IIBP document.

PureMVC was created to make it as easy on the developer as possible. I knew very well what the Mediator's role was and I made the decisions I felt supported that role best.

If after this, you still feel the need to abandon the built-in way of doing things, then by all means feel free to do so. I went out of my way at every turn to ensure that any decision I made was something that you could override/reimplement if you didn't care for the way I did it. That's why every single class has an associated interface and the framework handles interfaces and not classes where ever possible.

See my notes above for how you might go about overriding this behavior.

-=Cliff>
Logged
lizardruss
Newbie
*
Posts: 9


View Profile Email
« Reply #5 on: August 30, 2007, 05:20:19 »

Hi Guys,

First, great job on PureMVC, Cliff.

I wanted to pipe in on this discussion because today at work I implemented an alternative Mediator.  From the looks of the discussion, someone else has had the same idea.

Here's a quick overview...I extended the Mediator provided by the framework and added a method registerNotificationHandler(notificationName : String, handler : Function) : void. Internally, the mediator maintains a Dictionary of notification names, each with an associated ArrayCollection. Each time registerNotificationHandler is called, the function passed in is added to the corresponding Dictionary entry. This allows a generic implementation of listNotificationInterests and handleNotification. listNotificationInterests now simply returns the keys in the Dictionary. Similarly, handleNotification gets the Dictionary entry for the notification and loops through the collection, calling each handler function.

This adds a little bit of power to the mediator, since now you can add multiple handlers for each notification.

Relating to the current discussion, I'd like to offer an alternative way of looking at the switch statement.  Each case, no matter how simple the actions inside may be, is still a unit of work.  As a matter of preference, I like to put units of work into functions. However, at the end of the day, to switch or not to switch is a matter of preference.

That having been said, I would suggest allowing users to contribute alternative implementations of PureMVC interfaces to expand the framework. As a user of the framework, I'd like to have the option of using one implementation over another when I have a use for it. As Cliff has said, the user can take it or leave it as they please.  Allowing contributions to the framework, however, gives users access to common solutions instead of having to roll their own.

I realize that accepting contributions would need to under go some review process to make sure the appropriate unit tests and documentation are provided.  If PureMVC was mine, I wouldn't want contributed code marring its reputation.

At any rate, I guess my overall thought on this discussion is, "Why not have both?"

Cliff, what are your thoughts?
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #6 on: August 30, 2007, 08:39:10 »

Firstly, to answer the fresh question here, that of contributions. I do plan to open a contribution site. Absolutely and without question.

There are good things being done by people and the intention was to create a framework around which people would create useful classes and packages. How cool would it be to have a user contributed set of Proxies to talk to all kinds of major services out there ala Kiwi? Or how about an InterceptingFacade, that takes the notifyObservers arguments and pipes them off to a InterceptFilter before passing it on to the View? This would allow you to do tracking of a user's actions within the app, as well as just help you debug the notification traffic.

This kind of thing is absolutely part of the plan. In fact you might even want to license particularly useful PureMVC apps or utilities you make. I implemented the framework and now work with it daily, but can only do so much so fast. But the community is already coming up with the solutions that help the rubber hit the road, and their own takes on how things should work.

As to maintaining control of the idea space surrounding the core framework, I believe that this is an essential role of the architect. Design by committee has not been something I've seen work often in the past.

However a site with more opportunity for the community to engage, interact and contribute is on its way. Literally, my whiteboard is covered with it at the moment. As you said how do you control the 'quality' of what is going out there? Guidelines and tools to help you get your contributions into a normalized form so that everyone doesn't have to figure out how to publish and document their PureMVC thingy will help. Also communities seem to get on well with this rating thing. So a way of having a localized peer review of, for instance, an alternate mediator, is what's needed. That way your contribution, be it a single class, a utility, an app or whatever takes on a life of its own. In a way that allows people looking to use it really educate themselves about what they're doing. The forum will work for now, but believe me, a better plan is on the way.

Now from the 'Beating a Dead Medator to Death' department:

The fact that you can't do much inside the switch statement is intentional. The Mediator should not be doing that much work and because of its design, it is not intended to bolt onto the rest of the system in the manner that we use it to adapt components.

The automatic way it is hooked up to the system at view registration time and the use of a single method for handling notifications helps to support this in the same way that a 3/4" faucet stem encourages, specifically, a 3/4" hose.

The Mediator in PureMVC is not the same sort of beast as a ViewHelper in Cairngorm or 'code behind' in dotNet. In those characters their primary role is a way of taking all the code from the view component and putting it in a class, so you get good separation of what is code and what is view definition.

That's not the balance here. Here, the View Component accepts a little internal wiring code as a way of encapsulating itself and being portable (see footnote 1). As a way of creating a course grained interface to whatever uses it. Therefore a Mediator does not micromanage the fields of a View Component that it is adapting.

So a Mediator should not be setting and getting scads of properties. A Value Object is the right way to transport a big collection of properties into a view component and keep the Mediator's hands clean.

If transformation needs to be done to the data before it can be set or it needs to come from many places, that is business logic and should be carried out in a Command.

Also, by design, a Mediator's should not expose functions. This gives us the opportunity to CALL them. And that is a collaboration anti-pattern in this system.

All these design pressures lead to a Mediator implementation that adheres to the intended responsibility set and collaboration patterns.

-=Cliff>

Footnote 1: If you want code-behind on your MXML so its really clean just extend your MXML class with an AS class and add functions.
Logged
lizardruss
Newbie
*
Posts: 9


View Profile Email
« Reply #7 on: August 31, 2007, 07:35:02 »

I agree with you about the Mediator's responsibilities. I like your comparison of it to a fitting between the view and the framework. In the application I'm developing, I've made sure to keep any view logic in the view, and simply invoke it through the mediator.

As for the ViewHelper and code-behind patterns, after using Cairngorm for several projects, I decided ViewHelpers added complexity that wasn't helpful. Code-behind sounds like it does something similar for the sake of keeping behavior and markup separated.

I forgot to mention that in the scenario I described for using functions as handlers for notifications, the functions would be declared as private on the Mediator, and certainly not exposed to the rest of the system.

Having said that, I think we're on the same page conceptually on the 'Dead Mediator' so I'm done piping in on it.

I'm happy to hear that there will be a contribution site.  This is one thing that the other flex frameworks out there are missing, and will definitely help boost PureMVC's success.
Logged
Pages: [1]
Print