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: Notification to Command mapping...why the one to one?  (Read 12197 times)
sideDoor
Full Member
***
Posts: 25


View Profile Email
« on: January 20, 2011, 11:40:54 »

I've been building apps in PureMVC for over a year now, and it still bothers me that you can only map a single command to any notification.  I don't follow the logic in this decision.  The Observer pattern, on which event driven architecture is based, should allow multiple parties to uniquely and independently handle any one event.  I find this enormously restrictive that mapping a notification to a command will overwrite a previous mapping.  I would prefer being able to target the removal of a mapping based on the Notification/Command pair.

I don't feel macro commands are the answer either...if I want to allow one command to be fired on a given notification consistently throughout the life-cycle of the application, yet during a sub-cycle ALSO handle the same notification in some other way, I should be able to do so based on the Notification/Command pairing.  In the AS3 event model, you removeEventListener based on the pair of Event to Function signature, allowing other handlers to remain intact on the Event.

Why the restriction?
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: January 21, 2011, 06:11:42 »

The restriction is a by-product of the notification mechanism. The Controller class is actually the observer that is registered, and based on the note name it looks up the registration and triggers the corresponding notification and instantiates the command on the spot. Commands are short-lived, and are not created ahead of time and so can't be observers themselves.

The MacroCommand is equivalent to having multiple commands that are registered for the same notification. If you wanted to handle things differently at some point you'd need to manage registering and unregistering the new command anyway. So just create a different macro command with the appropriate set of children, unregister the first macro command and register the new one.

This is better, because if you're having a sequence of commands that process a note, then you probably care about the order in which they are processed. The MacroCommand gives you this control. You can't control that through command registration and unregistration, and mediators can be registered and unregistered from that notification's observer list as well. So at runtime, if you want to ensure those commands are executed in sequence, you need to use a MacroCommand.

-=Cliff>
Logged
sideDoor
Full Member
***
Posts: 25


View Profile Email
« Reply #2 on: January 25, 2011, 08:35:00 »

Cliff,

Thanks for the response.  Unfortunately, to me the one to one (note to command) mapping is a bit of a design flaw...

The simple fact that a developer can join my team and unwittingly overwrite a notification to command mapping by registering a command somewhere deep in the life-cycle of an application, and thereby change expected behavior or introduce hard to track bugs, is seriously problematic.

I understand that the Controller is receiving notifications as an observer, but the controller's map of notifications does not necessarily need to remain one to one, and certainly the un-mapping doesn't need to be done simply registering a new note-to-command or by passing the note name only to the removeCommand() method.

I'm still not understanding why you'd opt for this restriction.  Multiple actors should be able to respond to an Event/Notification, IMHO, and in this case, multiple commands mapped to one note is a much more powerful and flexible solution.  Safer would be to unmapped a command explicitly with the notification/commandClass pairing, to prevent new-guy from overwriting stuff by accident.

It wouldn't be hard for a refactor on this one, in fact, I'd vote to upgrade the notification to command mapping using a simple dictionary like so:
:
// inside the Controller //
private var _mapNotesToCommands:Dictionary = new Dictionary();

public function registerCommand(note:String, commandClass:Class):void
{
if (_mapNotesToCommands[note])
{
var commands:Vector.<Class> = _mapNotesToCommands[note] as Vector.<Class>;
if (commands.indexOf(commandClass) == -1) //prevent the same command being registered twice for the same note //
commands.push(commandClass);
} else {
_mapNotesToCommands[note] = Vector.<Class>([commandClass]);
}
}

public function executeCommand( note : INotification ) : void
{
var commands:Vector.<Class> = _mapNotesToCommands[note.getName()] as Vector.<Class>;
if (commands)
{
for (var i:int = 0; i < commands.length; i++)
{
var commandClass:Class = commands[i];
if ( commandClass == null )
continue; // perhaps give the option of loggin here //

var commandInstance:ICommand = new commandClass()  as ICommand;
commandInstance.initializeNotifier( multitonKey );
commandInstance.execute( note );
}
} else {
// perhaps give the option of loggin here //
}
}

Commands could be given execution priority (like Event Listeners in AS3), and other privileges, like permanent mappings, timeouts, or mappings based on states, er whatever...just thinking out loud here...

As well, I'd prefer to see an Enum-type Object used instead of Strings to represent notifications, more powerful with strict equality as well as giving the notification a 3rd dimension, in the Object Oriented sense...but...you know...Strings are good too.

Anyway, thanks.
« Last Edit: January 26, 2011, 06:42:54 by sideDoor » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: January 26, 2011, 11:06:44 »

The simple fact that a developer can join my team and unwittingly overwrite a notification to command mapping by registering a command somewhere deep in the life-cycle of an application, and thereby change expected behavior or introduce hard to track bugs, is seriously problematic.
'somewhere deep in the life-cycle of an application' is not the place to be registering commands. It indicates you already have a spaghetti-code project. This is why generally, commands are generally registered once at the beginning of the application. If you do things otherwise, then you should have a clear architecture document that describes when and where you register/remove commands. Even if you could register multiple commands to a given notification, the above could be true. The new command introduces the possibility of a bug whether it overwrote the old one or not.

I'm still not understanding why you'd opt for this restriction.
I didn't opt for a restriction. Rather I opted for a simpler solution over a more complex solution. With MacroCommands, the ability to have multiple commands responding to a notification exists. If you want to change the order of those commands or have a different set of commands respond in certain cases, simply create one or more additional MacroCommands that comprise the desired SimpleCommands and register/remove as appopriate. You have a solution that is indistinguishable from being able to have multiple commands registered to the same notification.

As well, I'd prefer to see an Enum-type Object used instead of Strings to represent notifications,
Again, the choice was simplicity over complexity.

Instead of defining a bunch of simple string constants for notification names, the developer would be forced to implement something like this:

http://svn.puremvc.org/Demo_AS3_Flex_EmployeeAdmin/trunk/src/org/puremvc/as3/demos/flex/employeeadmin/model/enum/RoleEnum.as

IMHO, Enums sit on the razor's edge of almost being too much hassle to implement for the worth they bring to the app. *Almost*. There are times when I've had to use them extensively in an app, and even transferring them as members to the server (on an object with lots of predefined settings), and there you have to go another level of hassle to clone them, or all you end up with all your similar combos changing in unison when one is changed. But still, they were worthwhile in their savings of validation code that didn't have to be written.

But, if all developers using PureMVC for anything were forced to use Enums just for notification names, the framework would never gain wide acceptance. The use of constants for notification names pretty much insures that you're sending the note you think you are.

-=Cliff>
Logged
sideDoor
Full Member
***
Posts: 25


View Profile Email
« Reply #4 on: January 26, 2011, 10:13:50 »

Hi Cliff,

I guess you're not buying my sale:

For encapsulation and decoupling, any object capable of dispatching an event should be able to do so without worry of executing a linear, singular response.  Any object capable of listening should be able to register and un-register an event-handler for the event of interest.

Does this make a program easier to follow? Yes, sure, if the role of the objects are clear.  But why use object-architecture if you want to script the flow of an application in one place?  And how scalable can that be? 

This is why generally, commands are generally registered once at the beginning of the application.

I think if you're really worried about seeing what can happen in an application at a given state, print a list of registered commands to the console...(I know, I know...blasphemy, but is Ctrl-clicking your way through function-calls in Eclipse a better way of following the flow of the Controller?)...One beauty of the Controller tier of MVC is simply that your events and responses can be visible at runtime BEFORE the events are fired.

Registering your commands at start-up doesn't make the application flow any more clear - simply because for one, events happen whenever, not in a linear fashion, and two, as mentioned, anyone can at anytime unwittingly un-register a command at any time - spaghetti code or not... Furthermore, flow charts and UML go along way toward helping the clarity of application and its flow, but reasonably speaking, design and implementation often part ways early and rarely meet again, and your employer would much rather you get on to the next project then update outdated diagrams...

I understand why it is in MVC that the Model should not be an observer but always the subject, but currently, the Controller tier of PureMVC is simply scripting a linear flow, spread across objects.  What if you want to respond to an event in two completely unrelated ways?  What if you want to sometimes respond to an event in one way, but also ALWAYS respond to the same event in another way?  In both these cases, the use of Macro Commands doesn't fly - the handlers are unrelated and the order doesn't matter.  And, if you were to use Macro Commands to do something like this, you'd have to register one Macro Command to the notification at some point in your application, and then register another different Macro Command to the same notification at another point in your application, perhaps deep in the life cycle of your application, which you're advising against...

...'somewhere deep in the life-cycle of an application' is not the place to be registering commands. It indicates you already have a spaghetti-code project.

Again, my point was actually that with the current implementation it IS possible for anyone to at any time register, overwrite and un-register a command from a notification, and given this lack of safety, it would make things more clear and safe to have to explicitly un-map a command from a notification using the notification/command pair.


Let me try you another way:

What would be wrong with implementing the registering, executing, and un-registering commands to notifications as illustrated above [un-mapping not shown]?  Wouldn't that be more flexible?  How would that kill the Pureness of PureMVC?

Thanks man!
sd.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: February 01, 2011, 01:12:23 »

anyone can at anytime unwittingly un-register a command at any time
Not so. If you register a Command, knowing full well that if one is (or may be) already mapped to that notification, and you don't check the registration first, then you have not unwittingly done anything, you've carelessly done it. The documentation for the registerCommand method clearly states:
If an ICommand has already been registered to handle INotifications with this name, it is no longer used, the new ICommand is used instead.

:
if (! facade.hasCommand( MY_NOTE )) facade.registerCommand( MY_NOTE, MyNoteHandlerCommand);
That's all it takes to ensure you've not 'unwittingly' overwritten a registration. And if facade.hasCommand( MY_NOTE ) is false and that's a problem for you, then you need to reevaluate your runtime Command registration strategy.

What would be wrong with implementing the registering, executing, and un-registering commands to notifications as illustrated above [un-mapping not shown]?  Wouldn't that be more flexible?  How would that kill the Pureness of PureMVC?
The reason it's a tough sell is that this code has been stable for several years now, bug-fixed into maturity with many eyes. Almost every bug fix along the way that required a major reimplementation of some method lead to some new problem. That leaves a lot of developers dependent on shakey code and having to be checking all the time to see if there is more stable code available.

And once we'd bug-fixed this simply-scoped framework into maturity, it began to be ported. Which adds a new level of pressure, because the ports follow the changes at different rates. Some right away, some not. So if the inevitable bugs or non-featurelike-behaviors that such a change is bound to bring with it aren't flushed out for awhile, then that means there are ports that have the bug as well, and that now need to be updated.

So what seems like a change to a core method can have alot of repercussions throughout the community in terms of people's time. What happens to code that depended upon the understood behavior all this time? It breaks if they upgrade to this or they have to rewrite.

My allegiance in matters like this must be to the development community that has relied upon the framework for its stability and predictability. I don't see an argument here that shows that anything is broken (i.e. does not work as advertised), and the scope and features were frozen years ago to achieve this goal.

BUT:
The lovely thing about PureMVC is you can do that long hours were spent ensuring that if you didn't like any part of it, you could modify that easily. You can make your suggested modification locally in one of two ways:

Modify the source, (it is Open Source) just check out the project or download the archive, create a library project and modify the source, producing a new swc library for your use. This isn't really recommended. Like branching, it's just better off not done. But it is an option.

OR

Extend the View class, override the methods you want to change and in your ApplicationFacade, override the initializeView method and instantiate your own View sublcass (see how to do this in the initializeView method description in the API doc1). Or if you don't want to extend you can just implement the IView interface. I made sure that if you needed to swap out the core actors for ones of your own, that you could do so while using the rest of the framework as is.

Cheers,
-=Cliff>

1http://puremvc.org/pages/docs/AS3/standard/framework_asdoc/
Logged
sideDoor
Full Member
***
Posts: 25


View Profile Email
« Reply #6 on: February 04, 2011, 02:28:06 »

Cliff,

I completely understand, thanks for the volley and your time in explication!

Much appreciated!

sd.
Logged
ChSemrau
Newbie
*
Posts: 5


View Profile Email
« Reply #7 on: February 16, 2011, 03:02:26 »

Extend the View class, override the methods you want to change and in your ApplicationFacade, override the initializeView method and instantiate your own View sublcass

Just wanted to note that this is not sufficient. In the current implementation, the Facade invokes initializeModel, initializeController and initializeView in that order. The Controller calls View.getInstance(), before the Facade calls the overridden initializeView, and so the Controller gets the wrong View class.

A possible workaround is to also subclass Controller, override its initializeController method, and in the ApplicationFacade, override initializeController to instantiate the subclassed Controller.


I subclassed all three core actors, and overrode their register methods so that I get an Error if any Proxy, Mediator or Command is registered for a name that is already taken. This way, I get notified during testing when someone "unwittingly un-registers a command". I even produce a stack trace of the first registration and supply it in the Error message upon the second registration attempt, so I can easily jump to both source lines. Also, recently, I overrode the retrieve methods, so I get notified about not-yet-registered proxies (happens more than once during development), instead of having to interpret the inevitable null-Error.

Regards,
Christian
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #8 on: February 20, 2011, 11:19:36 »

Sorry for that omission in my response, you do have to override Controller as well. It is mentioned in the documentation for the Controller class:

initializeController   ()   method   
protected function initializeController():void

Initialize the Singleton Controller instance.

Called automatically by the constructor.

Note that if you are using a subclass of View in your application, you should also subclass Controller and override the initializeController method in the following way:

:
    // ensure that the Controller is talking to my IView implementation
    override public function initializeController(  ) : void
    {
     view = MyView.getInstance();
    }
   

-=Cliff>
Logged
Pages: [1]
Print