Thursday, November 11, 2010

Conditional Logic and GUICE

For Contact Personal Assistant I am using GUICE.   After being introduced to Dependency Injection, or Inversion of Control, I appreciate its awesomeness, if I don’t fully understand it.  One of my main issues with fully adopting this paradigm shift, has been the usual barrage of questions a developer asks and answers in their own head in a daily basis, and the main one for me so far was.

How do I implement a conditional logic for an implementation instance based on runtime parameters?

Sounds a little abstract, I know.  So lets try an example.  Imagine you have a control which renders some information from a IDataServer interface but at runtime you have several Implementations of the IDataServer interface to chose from.

I have thought of many ways this could be achieved, but have known, them all to be hacky, my implementation based on how I currently understand GUICE, and trying to fit it into what I require.  As they say with great power comes great responsibility, and I want to use this framework correctly, not in hacked way that I can get it to work given my current level of knowledge.

It turns out the solution is as simple as it is beautiful:

USE MAP BINDER!

Luckily the answer is discussed on this thread which I replicate here:  

   1:  public class CalculatorModule extends AbstractModule { 
   2:     protected void configure() { 
   3:       MapBinder<Types, Class<ICalculator>> mapbinder 
   4:           = MapBinder.newMapBinder(binder(), Types.class, 
   5:  ICalculator.class); 
   6:       mapbinder.addBinding(Types.A).toInstance(ACalculator.class); 
   7:       mapbinder.addBinding(Types.B).toInstance(BCalculator.class); 
   8:       mapbinder.addBinding(Types.C).toInstance(CCalculator.class); 
   9:     } 
  10:   } 
  11:  @Singleton 
  12:  public class CalculatorFactory { 
  13:      private final Injector injector; 
  14:      private final Map<Types, Class<Calculator>> calculators; 
  15:     @Inject 
  16:     public CalculatorFactory(Injector injector, Map<Types, 
  17:  Class<Calculator>> calculators) { 
  18:          this.injector = injector; 
  19:          this.calculators = calculators; 
  20:      } 
  21:      public ICalculator create(UserGroup group) { 
  22:           injector.getInstance(calculators.get(group.getType)); 
  23:      } 
  24:  } 




This example uses a calculator factory to allow the user to select whether they want implementation A, B or C.  Simply inject the calculator factory into whichever class requires it.


Beautiful!

No comments:

Post a Comment