Mediator Proliferation
Hi, all;
I'm working on my first project where I am allowed a free hand on the architecture, so RobotLegs features prominently. I think maybe I'm going a bit crazy with it, because I find myself writing more than one mediator to mediate the same component (at the same time). If the task at hand doesn't require knowledge of what an existing Mediator does or knows and is different from the task the existing mediator handles, I find myself writing a separate Mediator.
This makes them incredibly easy to write, but I worry about whether this will be maintainable, especially when other developers start joining the project. I also worry about the performance hit of the extra code introspection.
Is this approach one that anyone else is doing, and if so, what is your experience with it?
Comments are currently closed for this discussion. You can start a new one.
2 Posted by creynders on 21 Apr, 2011 09:24 AM
It sounds wrong, but I can't really think of major advantages except one big one: if you come back to this project, or someone else needs to do changes you'll be searching in the mediators to find out where you need to do your changes.
It sounds to me though that this warns of an architectural flaw, maybe your components have too much responsibility and "do" too much? If the task at hand is different from the one the existing mediator handles chances are that task shouldn't originate from the same view component but from another (sub)component and therefore be separately mediated.
3 Posted by Amy Blankenship on 22 Apr, 2011 01:49 AM
It turns out that you can only have one Mediator per Context, per Class type, which seems like an unnecessary restriction. The only reason it worked was because I had nested contexts.
I don't think my Views have too many responsibilities...I just like tiny Classes. If it comes down to it, the Views I want to multiply Mediate don't have any responsibilities in and of themselves. They are visual representations of data the user is editing--exactly the same views that will be used to present the edited material to the end user. The Contexts and the attached Mediators and Commands add the editing functionality around the outside.
So, what I want to have is a Mediator that determines whether the represented data is in the selected data collection or not (based on mouse clicks on the View), another Mediator that updates the CSSStyleDeclaration for the renderer showing the data, and a third Mediator that opens Views representing textual data (based on an event generated when the user clicks a second time on the View representing the same data) for editing and propogates changes to the text back to the Model when the View is closed for editing. But unfortunately the MediatorMap actively prevents this unless I want to add extra layers of Contexts...and then I have to figure out how to manage all the communication and data among the contexts.
4 Posted by creynders on 22 Apr, 2011 05:51 AM
One solution would be to use the ViewInterfaceMediatorMap. You can have a view implement multiple interfaces and map each of them to a separate mediator.
That will solve the one big problem I described above as well.
But still, it sounds to me you're grouping too much in one view.
5 Posted by Stray on 22 Apr, 2011 04:52 PM
Can I just check - some of this sounds to me like you've started using the Mediator for a view Controller?
While the Mediator commonly sits in the view package (because it's nice and easy to see which views have mediators that way), it's a bridge between the view and application, not part of the view tier itself.
I could be wrong - but if that's how you're using it then that's the crux of your problem.
Alternatively, just compose your mediators in the normal way that you'd use to share functionality in multiple configurations across classes. Again, it sounds to me like you're trying to push work on to the mediatorMap which doesn't really belong there (by asking it to handle the composition).
There are lots of reasons why the one-to-one mediator-view relationship was chosen, but if you want to make a multi-mediator-per-view version then do go ahead and fork it and fix it!
6 Posted by Amy Blankenship on 22 Apr, 2011 07:27 PM
Right, Stray...none of the functionality really has anything to do with the View in its purest form. You do a lot of eLearning, so you should understand this. Imagine that you have a screen of data that can have 1-n bits of formatted text, 1-n graphics, etc. So the pure View is a DataGroup that has an itemRenderer representing each piece of data, and each renderer is one of the Views I want to separate out Mediation on.
In editing mode, I need to add more functionality than the "dumb" displaying of the data, to make it easy for users to see what is being edited and to make the Views behave properly while being edited. In most cases, the Mediators are merely firing events to move the Views into or out of selected state, but in some cases, either because of the limitations of binding or because the pure View should not have any facility for highlighting (this is not needed by the View in the end, edited state), the Mediator needs to do some work to make sure that the View state visually reflects the state of the data.
I am not willing to add logic or components to the Views to facilitate editing, but I don't see this as a problem. What I do see as a problem is the artificial restriction on multiple mediators imposed by Robotlegs. If I want to have Mediators that listen for click events from the View in the editing.selection package and other mediators that listen for "open for editing" events from the event bus in the editing.editing package, isn't that really my own business? It sticks in my craw that my editing mediator needs to extend the selection one, simply because of some stupid restriction in the Framework I'm using.
creynders, I'm not sure how I could put less in my Views, which are simply dumb displays of data objects, so I don't follow your point.
Support Staff 7 Posted by Stray on 22 Apr, 2011 08:47 PM
Hi Amy,
I think you mean "some work needs to be done", and not "the mediator needs to do some work"... and you've complete ignored my suggestion that you could compose your mediators to achieve the same pick-and-mix results, and creynders suggestion to use the Interface based mediatorMap utility, but anyway...
The Robotlegs framework is built to be the 20% of functionality that solves 80% of people's problems, as efficiently as possible. Not just for run-time efficiency, but also to minimise the cognitive load created by the framework API.
You are in the very small minority who have found a case where you would like a many-to-many 'mediator' situation. It's not that we've 'stupidly restricted' it - you don't have a god given right to multiple mediators that we've taken away from you out of idiocy. We've provided (free) a framework which enables a single mediator for each view, because this satisfies almost all use cases.
If you would like to further contribute to the framework as well, by creating an implementation of the mediatorMap which adds the feature of multiple mediators-per-view, feel free. Open-source is all about sharing the load. As we always say: fork it and fix it.
If you don't feel yourself to be capable of that, then perhaps have a little more respect for the people who do get the work done to publish the tools that allow you to earn your living more efficiently. We all have our weaknesses and limitations, and no doubt there are some things that will change in RL 2 because of the learning that comes from using-it-in-the-field, but the team (Shaun, Joel, Robert & Till) behind Robotlegs are among the least stupid people I have ever come across.
If you do feel yourself to be capable of building an alternative multiple-mediator implementation then get on with building it.
Yes, it's certainly your business how you choose to use the framework, but calling the implementation 'stupid' just because it doesn't work how you currently want it to work is an interesting way to go about engaging with the open-source community.
You've been offered sensible work-arounds by people who are also giving their time and energy free to try to understand your problem and offer solutions. You have a very strange response to those genuine gestures of assistance.
We don't really do flaming and disrespectful criticism here.
I'm guessing that you don't intend to be offensive, and you're just very frustrated with your code at the moment. If you want more details about how to implement one of the alternative solutions I'm sure people will be happy to help with a more detailed suggestion if you can provide some sample code as a starting point.
Thanks,
Stray
8 Posted by Amy Blankenship on 22 Apr, 2011 09:53 PM
Hi, Stray;
I'm a bit confused. What I was saying is that I actually do want to compose Mediators, to use one per "thing" that I want to do. I'm also not asking for a many-to-many mediator situation, but instead a many to one situation (many Mediators all mediating the same View, each with its own thing it cares about).
The reason I call the restriction stupid is that I can't think of any technical reason why you couldn't allow this to happen--it was my belief at the time that I said it that you probably could simply stop throwing the error and allow people to do this if they wanted to. Looking at the code, it seems that the reasoning behind this problem is that the MediatorMap has a dictionary that looks up one mapping per View Class.
And you're right, following the pattern used in the CommandMap Class to allow multiple Commands to be mapped for the same Event would be slightly less performant, as it would require nested Dictionaries (or you could use a Chain of Responsibility pattern, which might make the performance come out about even). However, if it is good enough for the CommandMap, which arguably will be mapping and unmapping more often than MediatorMap, why wouldn't it be good enough for MediatorMap?
The fact that the different parts of the Framework don't behave in the same way is certainly unexpected, and I might argue that this inconsistency creates more cognitive load.
You're also correct in that I have only a limited amount of time to work on side projects and this time is almost entirely spoken for, so it is unlikely that I would be able to patch MediatorMap and contribute it back to the community (though I might well just patch it for myself, since that would not require all the git setup, etc.).
I have never understood why people equate "I don't like what your code does in this instance" with "Your code is stupid and so are you, " and honestly I hadn't expected it to be taken that way by this group of people, particularly you. I deeply apologize that what I said in a moment of thoughtlessness affected you in this way.
I am not sure if the workarounds are actually sensible, as with the exception of ViewInterfaceMediatorMap I haven't been able to see a connection to my actual issue. That may be that I am not understanding what I am being told, but equally, it may be that I haven't communicated effectively what I am trying to address.
The reason I didn't reply to the suggestions about the ViewInterfaceMediatorMap is that I considered its possible appropriateness obvious, but I haven't yet had time to consider whether it will require implementation of multiple interfaces which will violate my goal of no logic that has anything to do with editing in the final displayed views. I can be as inflexible as you in preserving purity of intention in my code :-).
I'm not frustrated with my code, per se, because it works. Instead, I am frustrated by being forced to put things in places that make no sense according to how my code should be organized and to violate SRP, in effect by the very Framework I selected to allow me to do the opposite. This is very similar to the frustration I feel in working with TLF and realizing that a lot of its transformations go on entirely in the View and there's no way to picture them in data.
While there's no deity-of-your-choice-given right to anything in this world, it's disappointing to find that you've gotten so far down the road and the mechanics of the tool are dictating decisions for you. I was talking to a friend at 360Flex who is having a similar experience with Mate.
Anyway, you're right that I was not intending to be offensive, and I apologize again for having been offensive.
9 Posted by creynders on 23 Apr, 2011 11:24 AM
Hi Amy,
I didn't mean that you should put less in your views, I meant that what you see as one view is in my opinion more than one. But obviously I don't know the exact case, so it could be it really IS impossible to further break it down. Anyway, I think you do know now how to solve the problem, right?
10 Posted by Amy Blankenship on 24 Apr, 2011 05:18 PM
Hi, creynders;
If I read you correctly, it seems you are saying that I should actually have one or more separate views to use during editing, rather than using the runtime view and using Mediators and Commands to add functionality to them. I have a number of reasons for not wanting to do that, but the primary one is that I want to make sure I'm truly offering WYSTWIG editing--if they are, in fact, editing the actual View that will be used, you can't get much more fidelity than that.
I actually have never had an actual problem, per se, as it is always possible to get the logic to do what you want. This is more of a philosophical discussion as to whether my Mediation approach makes sense. And there's the issue that we have a third layer that we may choose to implement in the future--a practice layer, where we provide guided practice on top of the editing layer. And when we get to that layer, it will be really important to maintain clarity and good architecture.
At that point, it may make sense to just extend the editing Mediators to add on functionality to guide the practice, but it may equally make more sense to have independent Mediators. When I get to that point, I'll come back and let you know how it went :-).
11 Posted by Weyert on 30 Apr, 2011 11:05 PM
Hello Amy,
I am normally solve these kind of design mode issues by 'decorating' the plain view with a editing version which would offer the editing functionality. For example, if you have a text element which should be editable after a double click.
I would have a TextElement which renders text and then a EditableTextElement which takes an instance of TextElement which adds the editing related views. In my case a little toolbar for bold, italic and a tab stop ruler. E.g. new EditableTextElement( myTextElement ).
Next TextElement would have a method like setTextStyle and getTextStyle to change the formatting of the text. Of course, you could go with mediators but in the above example its a Flex component which encapsulates this all.
12 Posted by Amy Blankenship on 01 May, 2011 12:07 AM
Hi, Weyert;
That's interesting, but it's a completely different approach to mine. I personally don't believe in editing Views. Instead, I edit data as far as is practical, When the Flex Framework forces me to edit in the View, like changing the actual Test, I keep as tight control over that process as I can.
In this case, each Text (data) object has a separate member which describes its formatting. When the Mediator determines that the text has been selected, a reference to that formatting object is passed to the PresentationModel of the toolbar for editing. When the user changes the formatting, this launches a Command that edits the Model.
The problem is that something needs to call the toCSSStyleDeclaration on the styling object and set that style on the renderer that happens to be representing that data at the moment. But I absolutely will not compormise and make my View in any way aware of the fact that it is being editied, either for that or in order to highlight it.
Most of the issues I've seen with tight coupling and poor maintainability have to do with treating the View as integral to the editing process, rather than a means to collect user gestures that then can be translated into data changes on the Model by some other agency.
I'm actually using my Mediators for decoration, in order to add the communication needed and perform minor updates to indicated or assist with editing. Not everyone agrees that Mediators can/should be viewed as Decorators, but I believe that's as valid an opinion as any other.
When I get to the next phase, I will need to decide whether it makes sense to extend/fix MediatorMap to allow multiple Mediators to be attached to the same View Class, or whether I should just use two or more MdiatorMaps within the same Context. Because of course there shouldn't be any limit to the number of Decorators you can apply to the same instance---you should apply as many as you need and make sense.
Support Staff 13 Posted by Stray on 02 May, 2011 02:03 PM
Hi Amy,
you still haven't responded to the suggestion to simply implement the decorator pattern from within (or around) each mediator, rather than through the mediatorMap itself.
Nobody disagrees that decorator-mediators is a nice concept, it's just not in the 80% solutions that we target with robotlegs (which is why I objected to your calling it a stupid restriction - to me that suggested that the people who thought it was a reasonable restriction were actually stupid).
Mapping a single event to multiple commands is well within that 80% (even to implement bootstrapping requires multiple Commands mapped to the ContextEvents).
Multiple-mediators-per-view is - in our judgement - outside of the 80%. If it wasn't then you'd see a clamour of posts on here about it, where actually it has come up only 2 or 3 times in thousands of posts.
Definitely don't use 2 or more mediator maps within the same context. That would result in doubling (or more) the amount of heavy describe-type work being done in response to every single display object that hits / leaves the stage. Ouch.
I know you think that it's just a case of expanding the dictionary to have an additional dimension, but for various reasons to do with the clean-up process it's significantly more complex than that and would lead to having to do multiple checks when the view leaves the stage and/or a mediator is unmapped. The CommandMap deals with moment-to-moment situations, the MediatorMap has to deal with ongoing state issues, not to mention the flex-lifecycle (you'll notice there are about 6 workarounds for this in the mediator/mediatorMap code).
The mediatorMap is already the performance bottleneck in most Robotlegs applications. This is why we didn't integrate the excellent viewInterface version when it was offered - even a small performance hit is problematic, so we determined that it was better to offer it as a utility.
That said, if you do find a method for doing multiple-mediators without a loss of performance then we'd be really interested to see it.
I really can't see a problem with implementing the decorator aspect from inside the different mediators, except potentially losing state if you want to be able to change the decorator-configuration at runtime and your mediators are stateful (which they shouldn't be, ideally). You'd actually be switching out sets of mediators rather than decorating while leaving the existing mediators in place.
My best thought so far for a way around this is a MediatorDecorator utility which has the mediatorMap injected (so it can look up mediators for views) and wraps the decorators around the mediators as required. Mediators would then have to do some sort of clean up action on their own decorators when they are removed.
Your base mediator would need to be a DecoratorMediator that had hooks for these decorators. You have more detail about what you need to do, so I don't know whether this would actually achieve what you're looking for.
The first stumbling block I can see is that there's no way of guaranteeing that the mediatorMap is giving you back an instance of DecoratorMediator, rather than just a vanilla Mediator, so you'd need to think about how to ensure that your hooks are present. Most likely you could actually map the decorateable-mediators through your own utility rather than into the mediatorMap direct, and then you could cache the bone-fide types as you go.
If it does fix your problem but it's not something you have the time to tackle then I can put it on our todo list - which is a little long at the moment I'm afraid, but we'd get there eventually.
Stray
Stray closed this discussion on 25 May, 2011 08:31 AM.
Amy Blankenship (Magnolia Multimedia) re-opened this discussion on 29 May, 2011 04:56 PM
14 Posted by Amy Blankenship (Magnolia Multimedia) on 29 May, 2011 04:56 PM
Hi, Stray;
I am really sorry...your reply went into my junk mail folder :-).
The reason I don't want to implement Decorator _within_ the Mediator because
the Mediator would then need [Inject] variables for all of the Decorators it
is managing, even though the Mediator, itself, doesn't need that
information. One reason we use automated DI is because we've decided that
this is not good practice--Classes should only need to directly know about
information they're using, not information their children need.
Decorators _around_ the Mediators could potentially work, but seems sort of
fudgy compared to decorating the Views themselves, which is what the goal
really is. I don't believe you'd really need a DecoratorMediator, since the
whole idea behind decoration is that the thing being decorated has no idea
that it is involved in such a relationship.
MPO is that allowing more than one Mediator per view might be very close in
performance (possibly better) to having a separate decorator map that is
then traversing the mediator map.
It seems to me that all MediatorMaps in the same Context would share an
Injector (or is it the Reflector that does that bit?), so wouldn't that
shared Injector/Reflector do all of the describeType work? My understanding
is that once this is done once for a Class, it is cached and reused for
future requests.
I think the biggest issue for trying to allow MediatorMap is backward
compatibility--unmap doesn't have a parameter to allow you to just unmap one
of multiple different mappings for the same thing. For backward
compatibility, what do you do when someone has multiple mappings and calls
unmap() without a parameter that says which one?
I was actually surprised to read speed tests recently that show Dictionary
access is actually much faster than I thought
(http://www.zombieflambe.com/actionscript-3/as3-dictionary-class-array-object-benchmark/),
so I don't think having multiple MediatorMaps sharing the same
IInjector/IReflector would necessarily have performance issues. Since each
map would handle its own adding and cleaning up, I don't even see a
performance hit with that.
Thoughts?
-Amy
--------------------------------------------------
From: "Stray"
<***@tenderapp.com>
Sent: Monday, May 02, 2011 10:03 AM
To: <***@magnoliamultimedia.com>
Subject: Re: Mediator Proliferation [Questions]
15 Posted by Stray on 29 May, 2011 05:52 PM
Hi Amy,
it's not the injector that is the bottleneck, it's the listening and interrogating every single thing that winds up on the display list. If you have 2 things listening you double that work.
Every item - most of which are not useful - would be checked more than once. The mediator cache (which directs view classes to mediator classes) is not part of the injector (the injector / reflector are in a layer which is separate to architecture), and the contents of one cache and any other wouldn't necessarily be the same, so it's hard to see how this part could be sped up. In addition, there is a problem with caching in general in the mediatorMap, because mappings are dynamic, and so it's not straightforward to manage the state of the cache, as rules may get out of sync with mappings over the course of the app's lifetime.
So - having more than one map is going to be difficult to optimise. Which isn't to say it can't be done - but the implementation would be quite different from the existing mediatorMap, so simply implementing multiple instances of that mediatorMap is not a viable solution, and does cause substantial slow down in a project where views are frequently coming and going.
As you can see... simply deciding what 'decorator mediator map' means in terms of API is not trivial. There's quite a big difference between what a many-to-one mediator map and a one-to-one mediator map need. The issues around unmap are - as you say - unclear.
I don't think the mediators would need to inject variables for all the decorators - surely they would only need a single factory to be injected? You'd use a command to configure this factory with mappings against the mediator and view types (just as you do with the mediatorMap against view types), and the whole thing would flow from there - something like...
public class SomeMediator {
[Inject]
public var decoratorMediatorFactory:IMediatorFactory;
[Inject]
public var view:SomeView;
protected var decoratorMediator:IDecoratorMediator;
public override function onRegister():void
{
// may as well pass classes as we know them, avoiding the need to describe type
decoratorMediator = decoratorMediatorFactory.createMediator(SomeMediator, SomeView);
decoratorMediator.onRegister();
}
public override function onRemove():void
{
decoratorMediator.onRemove();
}
}
At run time you would then use the decoratorMediatorFactory to manage the adding / removing of decorators from any particular view while the view is live, using the decorators like a linked list: splice the chain simply by adjusting the parent/child relationships. I imagine that would be quite efficient.
Even better - the injection of the factory and the basic creation / removal logic could be shifted to a base class that you extend instead of the vanilla Mediator - though I think you'd lose the benefit of passing the classes rather than the instances of view and mediator.
This implementation isn't perfect of course, it's just what I've whistled up in a few minutes - but my point remains that it's *relatively* simple to implement a decorated-mediator approach using the existing mediator map implementation with some very minor additions.
Out of interest - what's your reasoning behind the comment that things-being-decorated-don't-know-that-they're-decorators? My understanding is that the decorator pattern implies composition, where the decorators have a reference to the component below them in the chain. They're ignorant of their parent, but they're aware of their child (ie they're like a linked-list with next but not previous) - otherwise how could one implement it? That makes me think maybe you didn't mean decorators after all?
Perhaps you meant covariance? There's an interesting spin on covariant mediators here: https://github.com/dnalot/robotlegs-utilities-variance
I'm not sure whether it's production-ready yet, or whether it fits your needs.
We're about to start the process of scoping Robotlegs 2 in earnest (at the end of June), and we'll certainly be considering mediators and the mediatorMap as part of that. If you do have time before then to at least scope the behaviours you're looking for then we'll throw it in the pot.
In an effort to keep it light, it's unlikely that RL 2 will (out-of-the-box) implement all the extra features people have requested (that would be impossible). But we will be paying attention to making sure that we provide hooks that support these kinds of extensions. It'll still fall to the first person who wants the functionality enough to actually build it to provide the initial implementation, but if people can clearly describe what they need then we can at least make efforts to support that process.
Stray
16 Posted by Amy Blankenship (Magnolia Multimedia) on 29 May, 2011 06:46 PM
Hi, Stray;
Perhaps you could do some sort of guarded event mapping shared between
multiple mediatorMaps to allow them to handle the listening and reacting to
newly instantiated Views (where one guard can call multiple result
functions). Perhaps Signals could be used for this, but of course that then
creates a dependency to another Library.
I see what you mean about injecting the factory, because at that point you
can also let the Injector inject dependencies that the Factory needs to
create the Decorators. I was assuming more that you were using it where the
Mediator is also creating new Decorators, which also violates a couple of
different rules ;-). It seems that if you take the approach that you
advocate below, you might as well just use child injection rules and
determining which child you get based on some other value you receive by
injection--the Injector is itself a Factory, so might as well make use of it
in this situation.
That might, in fact, be an effective way to deal with this situation. I
will think on it further and see if I can put together an example that uses
this, as even if I can't get it into git I can post it to a blog and it
should still be useful.
To answer your question: Yes, the decorator knows about what it is
decorating. But the thing it is decorating has no idea it is being
decorated, and doesn't provide any additional functionality to allow for it
to be decorated (besides something like events, that can be used by
decorators or anything else).
I believe the covariant Mediators is pretty much the opposite of what I am
looking for--it allows you to Mediate multiple subclasses of the same View
base class with the same View. I'll admit this is something I've wanted in
the past--until all the sudden I was showing miniature versions of the same
View as a thumbnail and I needed to turn off Mediation, which was easy to do
with a stub subclass. :-)
OK, I had a blog post planned for today, so must...stop...discussing. For
today at least ;-)
TTL;
Amy
--------------------------------------------------
From: "Stray"
<***@tenderapp.com>
Sent: Sunday, May 29, 2011 1:52 PM
To: <***@magnoliamultimedia.com>
Subject: Re: Mediator Proliferation [Questions]
Support Staff 17 Posted by Stray on 03 Jun, 2011 10:43 AM
Hi Amy,
the injector wouldn't have the onRegister / onRemove etc logic. So I think that would be a solution of limited use. I'd also prefer to see a strong-typed solution that declares intent whenever possible... and an API that limits the scope appropriately. If you just inject the normal Injector into the mediator then you have access to a powerful API most of which is not relevant in that context.
Anyway - I'm sure you'll figure something out when you're of a mind to build it.
Stray
18 Posted by Amy Blankenship (Magnolia Multimedia) on 05 Jun, 2011 02:06 PM
That's not what I was talking about. I agree that you shouldn't inject the
Injector itself except in really exceptional circumstances.
The ideal syntax would look something like this:
injectorForViewA = injector.createChild();
injectorForViewB = injector.createChild();
...
//default decorators
injector.mapClass(AbstractPurpose1Decorator );
injector.mapClass(AbstractPurpose2Decorator);
...
//specific decorators
injectorForViewA.mapClass(Purpose1DecoratorForViewA); //use default purpose
2 decorator
injectorForViewB.mapClass(Purpose1DecoratorForViewB);
injectorForViewB.mapClass(Purpose2DecoratorForViewB);
mediatorMap.mapView(ViewA, ViewAMediator, null, true, true,
injectorForViewA);
mediatorMap.mapView(ViewB, ViewAMediator, null, true, true,
injectorForViewB);
Both mediators would then look like:
[Inject]
public var purposeADecorator:AbstractPurposeADecorator;
[Inject]
public var purposeBDecorator:AbstractoPurposeBDecorator;
override public function onRegister():void {
purposeADecorator.decorate(viewComponent as UIComponent);
purposeBDecorator.decorate(viewComponent as UIComponent);
}
This is more typesafe than using
[Inject (name='injectorForViewA")]
public var purposeADecorator;
[Inject (name='injectorForViewA")]
public var purposeBDecorator;
and Rules, though there may be a way to handle this using rules already
where the mapView signature would not need to change and we could still
avoid having the Mediator know about the Rule's name. That's what I intend
to investigate before my next blog post about the Robotlegs Injector (the
first part is here
http://riarockstars.com/2011/05/31/understanding-the-robotlegs-injector-the-robots-are-running-the-factory/).
This whole discussion might be obviated by Till's upcoming toFactory() work
anyway, but it's worth thinking about, I think.
It seems to me that solving this problem in some way or other could be
useful, not just for this application, but for many others.
FWIW;
Amy
--------------------------------------------------
From: "Stray"
<***@tenderapp.com>
Sent: Friday, June 03, 2011 6:44 AM
To: <***@magnoliamultimedia.com>
Subject: Re: Mediator Proliferation [Questions]
19 Posted by Stray on 05 Jun, 2011 07:33 PM
Hi Amy,
now you've completely lost me. I thought it was the mediators you were trying to decorate, not the views?
So, why is the decorator decorating the view? Surely you want to be decorating the mediator? Otherwise you're implying that purposeADecorator is in itself another view - at which point this feels like the domain of the view map and not much to do with mediators at all.
This seems like it has now strayed a long way from the purpose of mediators (to provide event relaying for the view), so I'm not even sure that I understood your original intent correctly. I had thought that you wanted to be able to provide a single view with multiple mediators - yes? That was your original complaint - that it was a 'stupid' restriction ;) And that if only it was possible to assign 2 mediators to one view, all would be solved?
So - I'm obviously not on the same page in terms of what you're looking for.
If you do come up with a solution, feel free to share it with the community,
Stray
20 Posted by Amy Blankenship (Magnolia Multimedia) on 05 Jun, 2011 08:55 PM
No, my original intent was that Mediators ARE decorators of the Views, and
that you should be able to apply as many of them as you like, and they
should all be ignorant of each other. There are many ways in which a View
might be updated as a result of changes in the model, and it simplifies the
design of the Decorators (which also, in my original ideal, are Mediators)
if each purpose is served by a separate Mediator Class.
If the Mediators are decorating each other, they're not ignorant of each
other, are they?
The purpose of the Decorator might _affect_ the View (such as to highlight
it when it is "selected" or update its CSSStyleDeclaration when an Object
property changes from "normal" to "bold"). And, in fact, some Decorators
might well _add_ View elements without the knowledge of the View (such as a
button that would delete the object when it is clicked). And that element,
once added by the Decorator, would indeed be added to the Display List and
Mediated normally (until removed from the Display List by the Decorator).
But none of these things actually _is_ a View. It's a set of functionality
to be layered on top of a View. And there's no reason that the CSSStyle
decorator (or Mediator, ideally) needs to know about the Decorator that is
responsible for making sure a selected item looks and acts selected. And if
these Decorators can't be Mediators (which you assure me they can't), then
the Mediator should know as little about them as possible, and they have no
need to know about a Mediator.
Weyert suggested (and I considered it not to be a terrible idea in the
absence of multiple Mediators per View) that Mediators could be used simply
to apply as many Decorators as needed to a View. My biggest issue with that
idea was that I would not want my Mediators to know anything about how to
instantiate the Decorators or what they do. This could be resolved by
moving the instantiation part of creating the Decorator out to an Injector
and using it as a factory. However, it makes far more sense for the
Decorator to _be_ a Mediator, because the Mediator is already set up to both
know about the View it is Mediating and the Event Bus where the Events it
need to use to update the View are occurring. The issue is a technical
one--that the mediatorMap is simply not robust enough to allow this to
happen.
In your mind, the purpose of Mediators is to respond to Framework events,
but in my mind the Mediators are like miniature jockeys sitting on the backs
of incredibly stupid horses bred only to do one thing. I deliberately keep
my Views dumb, dumb, dumb, and my Mediators give them more direction and
functionality. This is especially important in the application we're
talking about, where the View has absolutely no idea it is being edited, and
all the editing functionality is being added to the View on the sly, through
Mediators. Also, it's so easy to inject the Event Bus into pretty much
anything, a Decorator, a PresentationModel, or whatever, that _only_ seeing
Mediators as event relayers isn't that useful IMO, unless you can use
mediatorMap to layer on as many Mediators as you need (more functionality
through Composition)--which, according to you, isn't feasible.
My intention has always been "How do I layer many independent Decorators on
top of my View," NOT "How do I decorate Mediators," which would be pretty
weird relative to my original question--it would suggest that I wanted the
Mediators to wrap around EACH OTHER and thus at least some of them would
know about each other. That's not my understanding of how Decorators work,
nor is it a concept I find especially attractive.
Keep in mind what happens if you have two (or more) independent Contexts,
both more or less looking at the same part of the Display list and a new
View is added to the Display List. If both Contexts have a mediator mapping
for the same View, you will get two different Mediators, unaware of one
another, both mediating the same View. Now, edit the eventDispatcher
injection mapping so that both are sharing an event bus. The behavior you
get in this situation is exactly what I want, but it doesn't scale. If you
keep overlapping more and more Contexts every time you want a new layer of
Mediation, you will eventually get a performance issue.
But I think that you're looking at this problem a bit too specifically--as
"how do we solve the Decoration issue," whereas the longer I look at it, the
more it becomes "how do I enable Mediators for different Views to get
slightly different information without resorting to magic strings." There
are probably lots of places where we could make use of Composition within
the same Mediator rather than creating a new Mediator for a slightly
different View/piece of data if we could do this.
The problem with using the ViewMap for this is that the View is actually
being Decorated, not being given information that can be injected into any
of its member variables--the View is completely unaware that any of this is
going on (and rightly so).
-Amy
--------------------------------------------------
From: "Stray"
<***@tenderapp.com>
Sent: Sunday, June 05, 2011 3:33 PM
To: <***@magnoliamultimedia.com>; <***@magnoliamultimedia.com>
Subject: Re: Mediator Proliferation [Questions]
21 Posted by Stray on 06 Jun, 2011 10:06 AM
Hi Amy,
While you're free to define the solutions to your problems any way you like, if the solution we provide isn't even a close match with your need then perhaps it's time to make your own, rather than attempt to bend the one we provided into submission?
You're redefining the mediator as a view controller - our mediatorMap implementation has only very limited support for this strategy. I don't have a disagreement with the dumb-view / view-controller set up - I just don't think using mediators (stateless yada yada) as view controllers is the only, or optimal, solution.
It's likely that we'll support view-controller creation through Robotlegs 2 in some way, but right now, as built, our mediator set up is not suited to this.
I still disagree that the meaning of decorator doesn't imply that the decorator can stand in for the thing being decorated... but anyway...
I just fundamentally believe that there is a simpler solution to your problem - one that doesn't involve using Robotlegs for anything other than a hook to kick off your custom behaviour.
I certainly don't think multiple contexts are particularly relevant. Yes, they would achieve the execution logic that you want, but you could use a totally inappropriate solution so solve almost any problem in programming - it doesn't really get you very far. (I seem to remember that that's what flash 4 and 5 programming was based on - using enterFrame loops to do all sorts of logic with invisible movieclips on stage all over the place!)
Maybe it's time to stop talking and get building? I'd be interested to see a proof of concept - the tests alone would clear up my confusion about what it is that you're trying to achieve.
Stray
Support Staff 22 Posted by Shaun Smith on 06 Jun, 2011 01:40 PM
Hi Amy,
Have a look at: https://github.com/dnalot/robotlegs-utilities-variance/
It provides covariant mediation (mapping mediators to interfaces, super types etc), which in itself necessitates multi-mediator mapping.
If you find it to suit your needs please post back here with feedback.
Support Staff 23 Posted by Shaun Smith on 06 Jun, 2011 02:49 PM
Ah, I see that this util has already been mentioned. Have you tried it out? You can map without covariance (third param):
function mapMediator(viewType:Class, mediatorType:Class, covariant:Boolean = true):void;
Ondina D.F. closed this discussion on 01 Nov, 2011 10:51 PM.