Extend Mediators
Hi everybody.
I was wondering how I could extend Meditors.
Just a simple example:
- I've got a site-engine which creates the single sites during runtime with the use of factory pattern. This means that I am creating a site object of type ISite in a controller and fire an event with this object as body. Then I simply add this object as a child of my site holder with the type Site
- every site is extending the Site class and implements the ISite interface
- every site has some basic communication with their mediators, but some sites do have an extended mediator communication
I want to implement one mediator, for example »SiteMediator«, which maps basic events of the view. But for some special sites I want a mediator which handles more events but the basic events as well. So I thought I could extend my »SiteMediator« and make a new mediator called »SpecialSiteMediator«.
I injected the view as »Site« in »SiteMediator« and the view as »SpecialSite« in »SpecialSiteMediator«. This does not work because of the redundant declaration of the property »view«. Injection the view only in »SiteMediator« as »Site« will cause this error »Error: Injector is missing a rule to handle injection into target [object SpecialSiteMediator]. Target dependency: com....::SiteMediator.as «
I hope you are able to understand the problem.
Thank you very much.
Roland
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
1 Posted by Roland on 14 Jan, 2010 06:04 PM
Sorry, could you please move this to »Problems«.... Thank you.
2 Posted by levi.strope on 14 Jan, 2010 08:49 PM
Hi Roland,
I could be completely off base with this solution but I'd love to be corrected.
I believe your problem is because you are trying to use an injected property of a super class in your concrete class
specialsitemediator
. In your case they are both concrete classes but you are treatingsitemediator
as an abstract.I do believe Robotlegs cannot inject into superclasses and have it available in your concrete class; you must define the dependency in your concrete class. My understanding of this is because it would cause far too much overhead to try to provide DI to non-concrete classes.
Essentially, you can extend your mediator but I believe your superclass should extend
MediatorBase
and then you could possibly define your view injection and then extend that class - I think that would work. But extending a class that extends mediator will not.Essentially I think you need to roll your own mediator class and not use robotlegs MVCS implementation of Mediator.
Does that make sense?
Check out this cheat sheet. http://andreitt.com/robotlegs/diagram/update/robotlegs_cheatsheet2.jpg
Here is what Mediator looks like:
package org.robotlegs.mvcs
{
(whats a good word for non-concrete classes?)
3 Posted by Roland on 14 Jan, 2010 09:31 PM
Hi levi.
Thank you for your answer.
When I tell the truth, I don't know what my custom mediator should look like or what I would change on the existing robot legs mediator.
If I only inject the view in my concrete class
specialsitemediator
and not in its superclasssitemediator
there is the problem, that I'm not able to map any events to the view in the superclass neither call functions of it. Maybe I got you wrong, but I need the injection of the view-superclass 'site' in the mediator-superclass 'sitemediator' and the view-concreteclass 'specialsite' in the mediator-concreteclass 'specialsitemediator' to map events and call functions.Sorry if I'm on the wrong track.
4 Posted by rw on 22 Jan, 2010 02:55 PM
I think I had the same problem. This is what I used for my solution. In my AbstractMediator, I had public var view:IView (has to be an interface). So When I map the view it Looks like this:
mediatorMap.mapView(View, Mediator, IView);
instead of
mediatorMap.mapView(View, Mediator, View);
So in the super Mediator you can access the view after the onRegister().
5 Posted by Roland on 22 Jan, 2010 03:00 PM
Perfect. Thank you very much for your answer. I will check this as soon as possible and post the result right here.
Thanks again.
Roland
6 Posted by Roberto on 11 Feb, 2010 06:20 PM
Hi guys,
I'm trying to do something similar, injecting a concrete class reference to its interface type, but with no success.
I defined a DataLoadCommand class.
In this class I have an injectedModel of type IMyModel
and an injectedEvent of type IDataRequestEvent. Let's speak about this.
In the AppContext I'm trying to map that injection using the injector with:
injector.mapValue(IDataRequestEvent, DataRequestEvent);
I'm using mapValue as the (concrete) DataRequestEvent is instantiated and dispatched from inside the mediator.
I think there is something wrong or I'm missing.
What I'm traying to do would be something like:
but I don't know how to do that...
Am I missing something?
Is it possible to inject a concrete class (reference) to its interface type with Robotlegs ioc?
Thanks a lot
Roberto
Support Staff 7 Posted by Till Schneidere... on 11 Feb, 2010 06:58 PM
Hi Roberto,
unfortunately, what you're trying to do isn't possible with Robotlegs.
The injector mapping for an event class to be injected into a command
is created dynamically by the framework during event dispatch; there's
no other way to inject the short-lived event instances.
Internally, Robotlegs looks up the type for each event and creates a
temporary mapping between that type and the current instance of the
event like so:
var eventClass : Class = event['constructor'];
injector.mapValue(eventClass, event);
var command : Object = injector.instantiate(commandClass);
injector.unmap(eventClass);
To be able to inject as an interface type, Robotlegs would need to
know about all possible interfaces the event could be injected as and
would have to create temporary mappings for all of them. That isn't
only impractical, it'd also be dangerous: An event might (for whatever
reason) implement an interface that's already mapped in the injector.
That mapping would then be overwritten.
What your mapping does is to instruct the injector to return the
*class* DataRequestEvent when asked for the interface
IDataRequestEvent. You're probably getting a type error on injection,
right? This is because the Flashplayer is trying to convert the class
to an instance, which naturally fails.
hope that helps,
till
8 Posted by Roberto on 11 Feb, 2010 09:10 PM
Hi tschneidereit,
thanks for your help.
Ok I understand the point even if I'd like to clarify that my idea is not to inject an interface but a reference to a class that implements that interface.
So for example I have something like:
[Inject] public var injectedEvent:IDataRequestEvent;
in the context mapping I will say that in the class DataLoader (for example) the member variable injectedEvent has to be injected with the reference to the concrete class DataRequestEventImpl (for example). I understand maybe it is wrong in this picture to talk about events as they are short lived etc.
Yes as you say I get a type error for a cast that (the flash player) tries to achieve but more than a cast it would be a promotion from a derived type to the base one. Isn't it?
Thanks again
R.
Support Staff 9 Posted by Till Schneidere... on 11 Feb, 2010 09:22 PM
If you want to inject instances as the interface type for long-lived
objects, you can do that by using the various mapping methods of
IInjector.
Right now, what you're trying fails because you're using mapValue, but
then supply a class as the value to be injected. Depending on your
exact usecase, you might want to use either
- mapClass - which creates a new instance for each injection:
injector.mapClass(IMyInterface, MyClass);
- mapSingleton - which creates one instance on the first injection and
then reuses that for subsequent one:
injector.mapSingletonOf(IMyInterface, MyClass);
- mapValue with an instance instead of a class
injector.mapValue(IMyInterface, new MyClass());
In all cases, you can specify an interface that the mapped value
implements and specify your dependencies as being of that interface
type.
If you absolutely must use this for events, you could create your own
temporary mapping while dispatching the event. Instead of
dispatch(new MyEvent(MyEvent.MY_EVENT_TYPE));
you'd write
var event : MyEvent = new MyEvent(MyEvent.MY_EVENT_TYPE);
injector.mapValue(IMyEventInterface, event); //temporarily map the
event to the interface
dispatch(event);
injector.unmap(IMyEventInterface); //remove the temporary mapping
10 Posted by Roberto on 12 Feb, 2010 09:42 AM
Ok. Thanks!
Till Schneidereit closed this discussion on 12 Feb, 2010 10:29 AM.