robotlegs / robotlegs-framework

An ActionScript 3 application framework for Flash and Flex
https://robotlegs.tenderapp.com/
MIT License
967 stars 261 forks source link

Retrieving Mediators for a given View #147

Closed darscan closed 11 years ago

darscan commented 11 years ago

Explore exposing a method on the MediatorMap to retrieve mediator instances for a given view. See #144

darscan commented 11 years ago

Also, it's worth noting that this method would return a list of mediators. In RL1 there would only be one mediator per view instance, but in RL2 a view instance can have many associated mediators.

Stray commented 11 years ago

Use case?

This would only make sense if the mediator had an API... and what RL returned wouldn't be guaranteed to implement that API. It's a bizarre way to use a mediator IMO when the purpose of the mediator pattern as implemented is to provide event-api translation / loose coupling. If you really need a mediator instance then you can send an event to which specific known mediators respond passing themselves as an argument - that way you have strong typed responses. Otherwise why not just use the view API directly? Or proper view controllers?

Unless this is purely for the extension building? i.e. wouldn't be on IMediatorMap and only on MediatorMap?

Sorry to chip in... I will now butt out again, it just didn't make sense to me, and we discussed why not to support it at length around a year ago, so I'm intrigued by why it's now a good idea.

darscan commented 11 years ago

and we discussed why not to support it at length around a year ago

Yeh.. something was floating around in the back of my mind telling me that we'd explicitly decided not to allow this.. I just couldn't remember exactly where or when.

so I'm intrigued by why it's now a good idea.

I'm not convinced it's a good idea, just opening up the discussion. Although I can see now that my wording was not great. Will amend.

darscan commented 11 years ago

Use case?

I did ask for one.. Over here: http://knowledge.robotlegs.org/discussions/robotlegs-2/3677-get-the-mediator-instance-for-a-given-view-instance-or-class

Stray commented 11 years ago

I think roll-your-own is so simple (just include a signal in your mediator, or an event handler, that will send the instance back) that it might be best to leave people to just implement it that way?

Then they not only get the benefit of bespoke strong typing, they also make it clear to the next developer (or themselves in 3 weeks) that this mediator gets used elsewhere.

Stray commented 11 years ago

However, if it does get implemented (perhaps just on MediatorMap), don't forget to slice(); :)

Matan commented 11 years ago

I've posted my use case on the knowledge platform, said it's waiting for moderation. :)

Stray commented 11 years ago

Hi @Matan - having looked at your example, there's no way the MediatorMap can robustly return a single instance, so I don't think it's possible to technically support this in the context of multiple-mediators-per-view. It would be really brittle to simply return the first instance. I guess you could filter a list of mediators returned, to find the right one, but that feels even dirtier. Also, if your piggybacking extension assumes one-mediator-per-view then possibly piggybacking isn't quite right?

darscan commented 11 years ago

said it's waiting for moderation

I think you need to register your email address on the knowledgebase to avoid that.

Matan commented 11 years ago

Exactly, piggy-backing wasn't my first approach, it was simply to copy the MediatorMap extension and adapt it. I did that and it simply felt wrong to clone the functionality as most of stayed the same. Also, extending extensions (for inheritance) in RL2 isn't really possible as the "interface return pattern" makes each and every extension quite concrete. The modularity comes at a price. ;-P

That said I opted for using the IMediatorMap instance internally while sapping from it what I can. All went well until the last little part that brings everything together, which is the behaviour implementations of the INavigationResponder instance.

Maybe as a solution to opening the API is to create a super-duper secret interface for the MediatorMap. E.g. The MediatorMap implements the IMediatorMap and IExtMediatorMap. Then inside the MediatorMapExtension create another super-duper secret injector mapping of the IMediatorMap instance to IExtMediatorMap. See where I'm heading with this?

Once someone really needs to access the extended API they can simply inject the IExtMediatorMap.

Shooting from the hip here, obviously needs more thought. :)

Stray commented 11 years ago

I'm afraid the un-extension-friendly-ness of the standard maps is intentional. Would it work to use an instance of the MediatorMap instead of extending it? [Oh, that's what you're already doing]. Then you can keep your own references for returning those specific instances of mediators, and pass the real work on to the MediatorMap? [Can't you do this by wrapping the one you're using?]

The reason for making everything private and locked down is that in RL1 we ended up with anything that was protected being effectively totally locked - which made fixing bugs kind of tricky, never mind improving performance / internal design.

Matan commented 11 years ago

I am using an instance of the MediatorMap at the moment, not an internally created one, but the normal one created by the MediatorMapExtension. This works perfectly well as that's exactly the functionality I need, only with one exception, obviously to access the mediator once it's been created.

Also, I would be able to handle multiple mediator instances if needed. The code I gave as the use case is merely a work-around for now.

I see the IMediatorFactory was recently removed: https://github.com/robotlegs/robotlegs-framework/blob/98178bd0a3afd81ca5a98d8bf1732c9b431c006e/src/robotlegs/bender/extensions/mediatorMap/api/IMediatorFactory.as

It would have been perfect for this instance and it allows the IMediatorMap to stay nice and clean. Any chance of bringing it back to life?

Stray commented 11 years ago

Not an answer to the IMediatorFactory question - but...

This is exactly what hooks are intended for btw - if you apply a hook it can have the view and mediator injected and then pass them to where you want to use them.

Matan commented 11 years ago

That is really good news. It didn't occur to me that the mediator instance is injectable within a hook. Thanks, I think I'll figure something out from here. :)

Stray commented 11 years ago

Excellent! Yes - this was the purpose of hooks, to give you a way to wire in to the lifecycle of the 'bits' that are managed internally in the framework/extensions.

Matan commented 11 years ago

Hi Stray, finally got round to implementing the hook. Was as simple as this:

protected function getResponderHook() : void
{
    _responder = _injector.getInstance(mediatorClass);
}

Thanks again.

Stray commented 11 years ago

Yay! That's exactly how I imagined hooks being used - tiny, weeny code but really powerful. Nice one!

darscan commented 11 years ago

Awesomeness! Closing this issue

redannick commented 11 years ago

Hi guys, I'm trying to achieve the same thing - using navigator-as3 with RL2, but I don't quite understand the solution. I've looked at the hook, but I think I'd need to hook for each type of view and mediator...? Matan, how did you implement your solution?

Matan commented 11 years ago

Hi, to understand the hook posted here, you'll need have the entire context of the extension I wrote. However, it boils down to the fact that right before the hooks are processed the Mediator Instance is mapped via the IInjector. Therefore, if you have MediatorClass in question, you can ask the IInjector to give you the instance of the Mediator within a hook. Have a look at how the mediators are processed: https://github.com/robotlegs/robotlegs-framework/blob/master/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory.as#L114

Hope that helps!!

redannick commented 11 years ago

Thanks Matan, what I don't understand is how to have a generic hook - I don't want to have to write one for each mediator/view pair with the strong types - or am I totally missing the point?

Matan commented 11 years ago

The simple answer is that I've written the extension in such a manner that the resulting "mapping" has reference to all the parts that are connected. Therefore, the hook can be generic. This is the function within my mapping instance:

public function withMediator(mediatorClass : Class) : IStateConfigurator
{
    _mediatorClass = mediatorClass;
    _mediatorMap.map(viewClass).toMediator(mediatorClass).withHooks(getResponderHook);
    return this;
}

Notice that I'm keeping reference to the MediatorClass. Thus once the hook triggers, I can ask the IInjector to give me the instance of the mediator. :)

redannick commented 11 years ago

ah...! I see. I was trying to hook via a Class, using injections for the mediator and view. Now I'm using a function hook per mediator mapping I can store the responders. Of course _injector.getInstance(_mediatorClass) only returns while in the hook.

Working!

Thanks for your help :)

Matan commented 11 years ago

Awesome :) Glad I could help.

imyellow commented 10 years ago

Thank you @Matan ,_injector.getInstance(mediatorClass); in getResponderHook is work. But I have a question, how can I know these things by myself? no docs can help, sees just one way is ask in issue and wait some one to answer it. Is robotlegs can make some example for learning all functions? then we can learn it by ourself, not need to ask, because I think you have no many free time, and sorry to bother you. Thanks again, it's very helpful.

Matan commented 10 years ago

@imyellow, the best advise I can give you is to look at the code itself, if the documentation isn't complete. The code will always tell you the full story. :) Also, it will give you insight into how these frameworks work, ultimately making it easier to make future decisions.