PureMVC Architects Lounge

Announcements and General Discussion => Architecture => Topic started by: benissimo on October 31, 2012, 03:12:34



Title: Re: Does anyone use a LayoutManager ?
Post by: benissimo on October 31, 2012, 03:12:34
Hi Tekool

thanks for your reply. It sounds like you are saying that the application needs some kind of StageMediator. This would be a mediator to instantiate and lay out a whole set of view components onto the Stage.

I originally designed my application in this way, but then decided that the entire view creation should be separated out into a PrepareViewCommand. I still use a StageMediator but this is now thinned down to be an actor that receives stage resize events and mouse and keyboard events and passes them on via Notifications.

If I were to move the view creation back into the StageMediator this would work, but it would also contain a lot of display logic. Decisions along the lines of "user has moved the mouse, so slide on the tools palette and - if user previously selected it via a checkbox in the settings - the status panel". This seems like a lot of logic to place inside a mediator which is, I thought, only supposed to catch events from the view and pass them back.

In summary then, I agree that a mediator (which holds references to all the various view components and takes full responsibility for their position, size and visibility) *would* work, but it feels like this is overloading the purpose of a mediator which is to be a lightweight actor.

Thoughts?


Title: Re: Does anyone use a LayoutManager ?
Post by: Tekool on October 31, 2012, 04:44:34
I originally designed my application in this way, but then decided that the entire view creation should be separated out into a PrepareViewCommand.

Keep this design, this is the right one. It is always better to initialize view components and their mediators (even if you initialize only one mediator for several view components) in a command. This the PureMVC way to manage dependency injection (http://en.wikipedia.org/wiki/Dependency_injection), using Mediator constructors.


It sounds like you are saying that the application needs some kind of StageMediator.

No, a StageMediator to directly manage view components is not the best idea. It would be better to have a dedicated Mediator for your group of MovieClips. One or several Mediator which name indicate what it does. When your app will evolve, a StageMediator can't be reused easily as it lays to the Stage only.

This seems like a lot of logic to place inside a mediator which is, I thought, only supposed to catch events from the view and pass them back.

When I say that a mediator can manage more than one view component I of course don't mean to place the whole app logic into one mediator. A single mediator only have to manage a group of view components having their own logic. But avoid to manage UI that do not share any logic into the same mediator.


Decisions along the lines of "user has moved the mouse, so slide on the tools palette

This typically has to be managed by your view component itself, not even the mediator. The mediator will only receive the event saying that the user as clicked on some of the tools of the palette. At least, it can receive an event telling to refresh the layout when deployed for any reason (what can be one of the answer you search for your LayoutManager question) then the mediator sends the appropriate refresh Notification to all other mediators. This sort of things happens often and is the right way of handling UI events to re-dispatch them to others UI component.


Title: Re: Does anyone use a LayoutManager ?
Post by: benissimo on November 01, 2012, 06:13:02

Keep this design, this is the right one. It is always better to initialize view components and their mediators (even if you initialize only one mediator for several view components) in a command. This the PureMVC way to manage dependency injection (http://en.wikipedia.org/wiki/Dependency_injection), using Mediator constructors.

I'm glad we agree on this :) I was very happy when I moved all the view component creation into a separate command. But this approach still has a problem that there is no central "manager" that holds any references to these components. A command to "GoFullScreen", for example, would not be able to access the view components in order to resize/reposition them.

...It would be better to have a dedicated Mediator for you group of MovieClips...
Isn't this effectively what a StageMediator would be? A dedicated Mediator for the top-level group of MovieClips?
There might also be other other Mediators that handle sub-components within the hierarchy, depending on how complex it gets, but at the top-level there would be a group of chunky components which require a mediator. Maybe ApplicationMediator is a better name? The group of MovieClips which represents the application.

When I say that a mediator can manage more than one view component I of course don't mean to place the whole app logic into one mediator. ...
No, me neither. The final decision of how many mediators will depend on the complexity and granularity of the overall system. I really meant that *any* logic should be moved into a command - which is difficult when the command needs to refer to a list of view components that spans the entire stage, and it is born with no immediate access to any of them.


This typically has to be managed by your view component itself, not even the mediator. ...
I'm not sure I agree with this. A view component can be responsible for its own contents, but it needn't/shouldn't be aware of anything outside of itself, such as where it is positioned on the screen. So layout considerations are something for an actor with a higher-level scope than the view component itself.


Title: Re: Does anyone use a LayoutManager ?
Post by: Tekool on November 01, 2012, 07:01:29
this approach still has a problem that there is no central "manager" that holds any references to these components.

which is difficult when the command needs to refer to a list of view components that spans the entire stage, and it is born with no immediate access to any of them.

Both those problems has the same answer : command can decide what one or the other view component must do through mediators. This isn't a problem for a command to directly access the mediator reference and uses mediator methods designed to interact with one or a group of view components. This is always better to use integrated mediator notification support, but when the logic is reusable, complex, it is still better to use external commands that directly drive some important mediator behaviors.

So you have to maintain references into one or several mediator, even if each of those mediator only have reference to one or several MovieClip holding references to many other child MovieClip in it. As you say this is a problem of granularity. This is here only your choice, but having a look at demos on PureMVC Github you will have a good idea of what is acceptable and what isn't.

I'm not sure I agree with this. A view component can be responsible for its own contents, but it needn't/shouldn't be aware of anything outside of itself, such as where it is positioned on the screen.

You certainly misunderstood me. Re-read what I say. I told that the UI has to dispatch an event telling the Mediator that an element has been clicked or that it has been deployed. The mediator decide what to do here, the UI never know any lower level application component here.


Title: Re: Does anyone use a LayoutManager ?
Post by: benissimo on November 01, 2012, 07:28:33
Ok, thanks for all your help and the ongoing discussion! I totally agree with the system of Notifications between Mediators. It sounds like its the Mediators that should be responsible for catching relevant messages relating to their view components.

I'm going to proceed along the following lines:

PrepareViewCommand:
instantiate view components
add view components to stage
instantiate mediators (all view components must be mediated at some level)
sendNotification( LayoutStart ) to set initial sizes and positions

LayoutStartCommand:
use stage width/height to determine position/size of all view components
retrieve all relevant mediators, call functions on them to set size and position of their respective view components

later, if user clicks 'full screen' button sendNotification( LayoutFullScreen )

LayoutFullScreenCommand:
use stage width/height to determine position/size of all view components based on new full screen layout
retrieve all relevant mediators, call functions on them to set size and position of their respective view components

... and I imagine creating a Command for each layout configuration which performs similar to above but using different size/position calculations.




Title: Re: Does anyone use a LayoutManager ?
Post by: Tekool on November 01, 2012, 08:51:33
All of your choices seems the right ones to me! ;)

I imagine creating a Command for each layout configuration which performs similar to above but using different size/position calculations.

Here starts the real application work, outside any architecture considerations. Just try to make your command reusable and maximize the use of Mediators methods for every operations that make view components specific operations like moves etc. that have no sense to make reusable in commands.

And sorry if I seem a little harsh in my answers, it's just that I'm really direct because English is not my native language.


Title: Re: Does anyone use a LayoutManager ?
Post by: benissimo on November 01, 2012, 09:51:40


And sorry if I seem a little harsh in my answers, it's just that I'm really direct because English is not my native language.

:) think nothing of it! I prefer direct, your English is fine. Thanks again for all your help I really appreciate it.


Title: Re: Does anyone use a LayoutManager ?
Post by: puremvc on November 01, 2012, 04:11:24
Hopping in a little late on this one...
I was very happy when I moved all the view component creation into a separate command. But this approach still has a problem that there is no central "manager" that holds any references to these components. A command to "GoFullScreen", for example, would not be able to access the view components in order to resize/reposition them.
The GoFullScreenCommand really doesn't make sense. The idea there is that the command retrieves the components and resizes them.

Mediators exist to decouple the View Components from the rest of the system. Have them be interested in the GO_FULLSCREEN notification, and have them invoke a goFullscreen() method on the component. The component should encapsulate its own state management. Now if you have a group of components, then yes, a layout manager component that contains them and can expose a goFullscreen() method for its mediator to call, and in turn make itself big and resize its children accordingly, then you're cooking with gas, and ready to grill.

If you look at Flex, this is how things are done.View logic needs to be encapsulated and managed within the view. You can push this burden back into the Mediator and Command classes, but it's ill-placed. Why? Because the Stage and the view components on it are the ones closest to the layout information, and it can be encapsulated there without affecting the rest of the program. You don't want mediators and commands full of code that micromanage the view because that makes it harder to change the view without changing tons of application code.

-=Cliff>



Title: Re: Does anyone use a LayoutManager ?
Post by: benissimo on November 04, 2012, 09:05:17
I can see why a lot of people have moved to Flex, it looks like it takes a lot of the strain in laying out and managing your components. I hope all you Flex developers out there appreciate the headaches you've been spared! :)

It would be a very interesting challenge to implement a "view framework" in AS3 that allow the entire view hierarchy to be specified in a flexible XML-style format, cascading resize events down the tree. If anyone's interested in taking this on I'd be happy to contribute.

For now let me share what I've implemented to get this idea off the ground. I'll also hopefully summarise and conclude (?) the above discussion on view hierarchies and God objects.

Firstly, I totally agree with the God object problem. I never intended the stageView component to be aware of every single view instance down to the last button in the bottom right corner.
But it does need to know all the "top-level" components (cf the User List, User Form and Role Panels in the Flex sample) and be smart enough to know how these components might change in response to changes in application state.
In my app, for example, I have half a dozen panels which slide on and off the screen depending on what the user is doing. The panels are black boxes to the stageView, it cares not for their contents, but the panels themselves are under direct control of stageView (eg changes to their position, visibility and dimensions).

The PrepareViewCommand instantiates the stageView.
The stageView instantiates the top-level components.
The top-level components instantiate whatever they want, they must take care of themselves and their children.
The PrepareViewCommand also instantiates a stageMediator to mediate the stageView, and likely further mediators for the top-level components (via references exposed by the stageView).

So far, so good (I hope).

Now, to quote from your last post:

You mediate at different points along the hierarchy as needed.

So what if we want a mediator for a view component which is nested several levels deep into the hierarchy?
The stageView doesn't know about this component, it knows only of the top-level components.
1. Allow the PrepareViewCommand to "reach in" and grab a reference to the view component by descending through the view levels via exposed references at each level (bad OOP!)
2. Component fires an "I exist, mediate me!" event which is caught by the stageMediator which then creates the mediator for it (slightly bad OOP! stageView *still* needs to know what the component is in order to create the correct mediator for it. Besides, at creation time the stageMediator doesn't yet exist)
3. Insist that only the top-level components are mediated and decide that this is exactly the right level of granularity for mediation. Hmmm... would work, but the tail is wagging the dog here.
4. ???

I'll leave that question open, maybe someone can provide a better number 4...


And here's a simple Composite pattern that I implemented to handle cascading resizes:
:
public class XSprite extends Sprite implements IXSprite
{
protected var _width:uint;
protected var _height:uint;

public function XSprite(_w:uint = 800, _h:uint = 600)
{
_width = _w;
_height = _h;
}

public function setSize(_w:int, _h:int):void
{
_width = _w;
_height = _h;
redraw();
}

// redraw must be overwritten in subclasses
public function redraw():void
{ }

}

public interface IXSprite
{
function setSize(_w:uint, _h:uint):void;
function redraw():void;
}


View components now extend XSprite, and must implement a redraw function.
Calling setSize on an XSprite allows a new size to be passed in, and the overridden redraw will then be executed.
The XSprite can redraw itself based on its new _width, _height properties and in turn call setSize on its children.
It wouldn't be too much extra work to extend this further to implement such as things as "VBox" and "HBox" as per the Flex architecture.


Title: ye
Post by: puremvc on November 04, 2012, 11:14:44
The PrepareViewCommand instantiates the stageView.
The stageView instantiates the top-level components.
The top-level components instantiate whatever they want, they must take care of themselves and their children.
The PrepareViewCommand also instantiates a stageMediator to mediate the stageView, and likely further mediators for the top-level components (via references exposed by the stageView).

So far, so good (I hope).
Yep.

So what if we want a mediator for a view component which is nested several levels deep into the hierarchy?
The stageView doesn't know about this component, it knows only of the top-level components.
Good question...

1. Allow the PrepareViewCommand to "reach in" and grab a reference to the view component by descending through the view levels via exposed references at each level (bad OOP!)
This isn't the best option, and the deeper it has to reach the more egregious a breach it is. If you're rushing through a prototype, this might be acceptable, but you'd never do it with production code.

2. Component fires an "I exist, mediate me!" event which is caught by the stageMediator which then creates the mediator for it (slightly bad OOP! stageView *still* needs to know what the component is in order to create the correct mediator for it. Besides, at creation time the stageMediator doesn't yet exist)
In Flex, where component creation may be deferred, this sort of handling is necessary. Well, you'd really not let it bubble all the way to the stage mediator, but to the mediator of the parent component. For instance, if the User Form instantiated a different subsection depending on the type of user, then the UserFormMediator would be in charge of mediating that subsection. This isolates the knowledge of what mediator to use for which component in the closest mediator to the action.

Another variation on this theme is to let the 'MediateMe!' event bubble all the top, and have the top level mediator catch it and then send it off in a notification to be handled by a command. It can have a switch that looks at the type of the component, (or a property from an interface all components expose), and for each case, mediates the event target with a given mediator. This works well, but it still isn't optimal to have commands handling view components, although it is acceptable from MVC perspective, in practice it's not so hot.

3. Insist that only the top-level components are mediated and decide that this is exactly the right level of granularity for mediation. Hmmm... would work, but the tail is wagging the dog here.
Nah.

Usually, if a mediated view component has a child that needs to be mediated, and that child exists at the time the view component is being mediated, then we have the mediator of the view component register the mediator for the child.

In fact, if the whole view exists by the time PrepareViewCommand is run, you can just mediate the StageView, and have the StageViewMediator (in its onRegister() method) register the immediate children. Then mediators can mediate the children of their own view components, ad infinitum.

This is really the most proper way to do it, because a Mediator is the only designated actor in the system that should 'know' a view component, and therefore have access to its direct children to mediate.

-=Cliff>


Title: Re: Does anyone use a LayoutManager ?
Post by: benissimo on November 04, 2012, 03:07:06
Awesome. I've totally got it. Sorted.

Thanks Cliff and Tekool for all your feedback, HUGELY appreciated! My coding is really starting to kick ass :)