Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Welcome, Guest. Please login or register.
August 16, 2017, 08:30:44 PM
Home Help Search Login Register
News: Please DM @puremvc on Twitter to gain forum access. Spambots are why we can't have nice things.
Pages: [1] 2
Print
Author Topic: Does anyone use a LayoutManager ?  (Read 7560 times)
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« on: October 31, 2012, 10:56:58 AM »

Hello Architects!

I'm using AS3 and I usually create all the various view components at runtime inside a PrepareViewCommand:

var chatView:chatView = new chatView();
var playlistView:playlistView = new playlistView();
var otherView:otherView = new otherView();
...
stage.addChild( chatView );
...
facade.registerMediator( new otherMediator( otherView ) );
...

of course this can get quite complicated with a hierarchy of view components:
parentView.addChild( child1View );
parentView.addChild( child2View );
child2View.addChild( child3View );
stage.addChild( parentView );
facade.registerMediator( new Child3Mediator( child3View ) );
...
... but I still believe this is ok.

What I'm NOT sure about is, what if the layout of all these view components needs to change? eg the user clicks a "full screen" button?

Now, a GoFullScreenCommand might have the responsibility of resizing, repositioning, adding and removing view components. But, aside from a gut feeling that a command shouldn't have to get so close to the gritty innards of the view, it doesn't hold references to them anyway! So all the view components need to be stored somewhere they can be retrieved and modified.

So I'm wondering if there needs to be some all-knowing LayoutManager which handles layout of all elements and switching between layouts. Like a StateMachine. But this would need to persist all the view components. In which case its now long-lived so its no longer a command. So what is it? A ViewProxy? But you can't proxy the view! A ViewMediator? But it contains lots of view-based logic. Help!

This is a question about instantiating a complex hierarchy of view components, and then later re-organising those same components into a different configuration. How would you do that in pureMVC? (Wow, two lines to summarise something that took a dozen paragraphs Smiley

Thanks,

Ben
Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW
« Reply #1 on: October 31, 2012, 01:58:35 PM »

Hello Benissimo,

You definitely don't need a ViewProxy. What you are looking for is simply the Mediator pattern itself. Have a look at its definition «The mediator pattern defines an object that encapsulates how a set of objects interact.»

I mean, PureMVC already offers the solution to your problem. When you have a set of view that can interact or can be grouped by any selection criteria, you must use a single mediator to manage them. You don't need to create one mediator for each «not so complicated» view component. Just be careful not to use a single mediator for too much view components that make no sense to group or at the contrary use a single mediator for let say, only a simple animated movie clip dispatching no event.

Something I made by the past and must be avoided as much as possible is to use a mediator to manage other mediators. It is best to use only commands and notifications in this case. There is always a solution to refactor the application not to have some kind of mega-octopus-mediator.
« Last Edit: October 31, 2012, 02:07:12 PM by Tekool » Logged
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« Reply #2 on: October 31, 2012, 03:12:34 PM »

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?
Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW
« Reply #3 on: October 31, 2012, 04:44:34 PM »

Quote
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, using Mediator constructors.


Quote
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.

Quote
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.


Quote
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.
« Last Edit: November 01, 2012, 05:54:18 AM by Tekool » Logged
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« Reply #4 on: November 01, 2012, 06:13:02 AM »


Quote
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, using Mediator constructors.

I'm glad we agree on this Smiley 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.

Quote
...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.

Quote
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.


Quote
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.
Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW
« Reply #5 on: November 01, 2012, 07:01:29 AM »

Quote
this approach still has a problem that there is no central "manager" that holds any references to these components.

Quote
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.

Quote
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.
Logged
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« Reply #6 on: November 01, 2012, 07:28:33 AM »

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.


Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW
« Reply #7 on: November 01, 2012, 08:51:33 AM »

All of your choices seems the right ones to me! Wink

Quote
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.
Logged
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« Reply #8 on: November 01, 2012, 09:51:40 AM »



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.

Smiley think nothing of it! I prefer direct, your English is fine. Thanks again for all your help I really appreciate it.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2870



View Profile WWW
« Reply #9 on: November 01, 2012, 04:11:24 PM »

Hopping in a little late on this one...
Quote
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>

Logged
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« Reply #10 on: November 02, 2012, 04:52:49 PM »

Aha! Well that seems to make sense... and different to the conclusions I'd come to. Thanks for hopping in Smiley

I've not used Flex yet, but it sounds like the view architecture is well structured. In AS3 then, might there be something like this?

1. A stageView or applicationView class (might not even need to extend sprite) which instantiates all the main screen components.
2. stageView is passed the stage in its constructor and adds all components to the stage.
3. stageView maintains references to all the components and takes full responsibility for adding/removing them from the stage and managing their layout.
4. stageView exposes references to some or all of the components so that mediators can be added to lower-level parts of the view.
5. stageView can respond directly to stage events (eg stage resize event) but also has a stageMediator which provides the connection to model and controller tiers.
6. PrepareViewCommand instantiates the stageView component (passing the stage to its constructor) and the stageMediator, and all the other mediators (passing the exposed child objects of the stageView to their constructors).

Does this sound reasonable?

If so, then great I can stop chasing my tail on this one!
Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW
« Reply #11 on: November 03, 2012, 05:17:34 AM »

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.

View logic must stay in the view at it maximum indeed, I wasn't clear enough on that point. I like this idea to talk about «micro-management» this well explain where the responsibility of a Mediator should stop regarding view components.

Quote
1. A stageView or applicationView class (might not even need to extend sprite) which instantiates all the main screen components.
2. stageView is passed the stage in its constructor and adds all components to the stage.
3. stageView maintains references to all the components and takes full responsibility for adding/removing them from the stage and managing their layout.
4. stageView exposes references to some or all of the components so that mediators can be added to lower-level parts of the view.
5. stageView can respond directly to stage events (eg stage resize event) but also has a stageMediator which provides the connection to model and controller tiers.
6. PrepareViewCommand instantiates the stageView component (passing the stage to its constructor) and the stageMediator, and all the other mediators (passing the exposed child objects of the stageView to their constructors).

Steps 1 to 3 will depend a lot on the design of your application, but what you expose here looks like what a lot of other AS3 PureMVC apps do. Steps 4 to 6 seems perfect to me too except the «instantiates the stageView component». In most designs the stageview is already instantiated there because we talk about the main view component of the application which also host the responsibility to initiate PureMVC itself.



« Last Edit: November 03, 2012, 05:22:01 AM by Tekool » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2870



View Profile WWW
« Reply #12 on: November 03, 2012, 09:45:27 AM »

Also, the idea of the StageView component being an all-knowing manager of every component leads to a bloated god-object. It might be alright if you only have a few children, but for an application where the nesting of components descends more than one level, your god-object now has to break the encapsulation of the components to 'reach down into' the hierarchy and manipulate things. This is contrary to good OOP design.

Instead, use the Composite1 design pattern to compose a hierarchy of components, each of which have the ability to have children added and removed and to manage their direct children. You mediate at different points along the hierarchy as needed.

We do need more pure AS3 examples, it is true, but for now, even though you may not have used Flex, I'm fairly sure if you look at the components I'm about to describe, you'll be able to understand what's going on. MXML is used to declare a hierarchy of components. These components can be containers, or controls (like combo boxes and buttons).

The example I'm going to point out is the PureMVC Flex EmployeeAdmin Demo, because it addresses this issue intentionally. Flex containers automatically lay out their children in a predefined way. You will need containers that do similar work.

First, here is the screenshot:
http://puremvc.org/pages/images/screenshots/PureMVC-Shot-AS3-Flex-EmployeeAdmin.png

You can see a panel with a list of users, a panel where a user's info is maintained, and another panel where the user's roles are maintained.

So, we break this into three major components, and the application (equivalent to your StageView component) instantiates only those components.

Here is the main application declaration:
https://github.com/PureMVC/puremvc-as3-demo-flex-employeeadmin/blob/master/src/EmployeeAdmin.mxml

The salient bit is this:
Code:
<!-- User Management Interface -->
<mx:VBox>
<view:UserList id="userList" width="100%" />
<mx:HBox>
<view:UserForm id="userForm"/>
<view:RolePanel id="rolePanel" height="100%"/>
</mx:HBox>
</mx:VBox>

Look back at the screenshot and then to this XML again. Ok, you can see a vertical box container is used to hold the three components. The list along the top takes up the full width of the box and we get the other two underneath it, in a box with horizontal layout.

You can see already that the responsibility for the layout is not on the application itself, but instead on containers it has as children. Those containers layout their children according to their own logic. The components may have their own sizes declared or the containers use default sizes based on how much room they have and what the component type is.

Now here are the three components themselves (UserList, UserForm, and RolePanel):
https://github.com/PureMVC/puremvc-as3-demo-flex-employeeadmin/tree/master/src/org/puremvc/as3/demos/flex/employeeadmin/view/components

Again, even if you don't know Flex, just realize that each of these MXML declarations is compiled into an AS3 class. They extend container or control components to get the layout behaviors and default sizes, which can be expressed as percentages.

So, you can see that incredibly complex view hierarchies can be composed without having a god-object doing the layout. It's a matter of having containers and controls that have the responsibility of managing their direct children and their own states.

Something that isn't totally obvious is how this all gets redrawn when, say the user resizes the browser.

Well, the application receives a RESIZE event and resizes itself and its children appropriately (the app is just a container with layout rules - can be horizontal, vertical, absolute positioning). As a result when those containers are resized, they in turn resize their children, and so on until the layout has adjusted to the new browser size.


-=Cliff>

[1] http://en.wikipedia.org/wiki/Composite_pattern
Logged
benissimo
Jr. Member
**
Posts: 13


View Profile WWW
« Reply #13 on: November 04, 2012, 09:05:17 AM »

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! Smiley

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:

Quote
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. Huh

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:
Code:
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.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2870



View Profile WWW
ye
« Reply #14 on: November 04, 2012, 11:14:44 AM »

Quote
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.

Quote
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...

Quote
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.

Quote
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.

Quote
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>
« Last Edit: November 04, 2012, 11:24:36 AM by puremvc » Logged
Pages: [1] 2
Print
Jump to: