↓ Archives ↓

dawn injectors multi-mappings

I just added a new feature to the dev branch of dawn, and since I haven’t got changelog files yet (bad sammy!!) I figured I would throw a post up so it doesn’t get lost. Seriously though, there will be a changelog :) This feature will make the next version of dawn, unless someone convinces me its bonkers.

I am aiming for dawns injector to be a complete injection solution (shiny bells AND whistles!!). Its not doing bad, but there are a few places that some polish wouldn’t hurt (better error reporting is a big on one those, its on the way).

This latest change was born out of a request from Mr. Tink. He wanted to be able to map one class (in singleton scope) to two interfaces. While such an exciting feat was possible previously, it really required knowledge of factory providers (and consequently some custom code). The new solution is much neater and is as simple as pie… I hope, O.K. an example:

Lets say I have a model object that implements a simple interface for views (or mediators or whatever said framework fancies). Simple, except that I also want methods on the object that shouldn’t be exposed to the view objects, so those can be added to an interface that extends the original one with the extra functionality.

// for dumb clients things like views etc
interface IAccessData {
  function getMyThing():Thing;
}
// for services/commands etc
interface IChangeData extends IAccessData {
  function updateMyThing(wibble:Wibble):void;
}
class ThingModel implements IChangeData { ... }

ThingModel implements both of these interfaces, and I only want one of my models to be created and that same instance to be injected for anything that require either IChangeData or IAccessData.

Previously I would have either had to map to a factory or an instance twice to get this to work, i.e.

// pray it has no constructor dependencies
var myModel:ThingModel = new ThingModel();
injector.map(IAccessData).toInstance(myModel);
injector.map(IChangeData).toInstance(myModel);

or

injector.map(IAccessData).toFactory(ThingModelFactory);
injector.map(IChangeData).toFactory(ThingModelFactory);

class ThingModelFactory { ... blah ... }

Either way, I have to create two mappings and its not so fun. If there was a third interface, or I wanted to also map the concrete class to the same instance it would require a third mapping.

In the next version of dawn (already in the dev branch) we can just do this

injector.map(IAccessData).and(IChangeData).to(ThingModel).asSingleton();

Ta Da!!

Much easier. Under the hood dawn still creates two mappings, its just sugar coated with the mapping DSL and our lovely ‘and’

Its also “chainable” (is that a word? I doubt it).. so if I also wanted classes that depend on the concrete implementation of ThingModel to get the same instance,  I could just add another ‘and’

injector.map(IAccessData).and(IChangeData).and(ThingModel).to(ThingModel).asSingleton();

And there you have it, multi-mapping goodness.  There are lots of other things coming soon, I just needed to get that one off my chest.

Also worth checking out is the asEagerSinglton scope that just made it into 0.8

3 Comments

  • Apr 8th 201009:04
    by Shaun

    Reply

    That’s pretty darn groovy indeed!

  • Apr 30th 201003:04
    by Glidias

    Reply

    This does get around the limitation RobotLegs has with the inability to map a singleton to multiple interfaces/classes. In RL’s case, I’m always forced to pre-initialize certain stuff in StartupCommand in order to force a live value instead (so much for defering instantiation..), which isn’t ideal in a large enterprise app, but okay for small/medium apps.

    • May 7th 201009:05
      by sammy

      Reply

      Hey Glidas, I havent used SwiftSuspenders but I believe it does have a solution to your problem. I notice in the docs “rules (which allows sharing singletons between multiple mapping rules)” … might help you out

      I dont think multi-mappings are enabling anything new as such, I’m just trying to make life easier :)

      Sammy

  • Leave a Reply