I think you'd be better off using a MapBinder.  The boilerplate of guice
essentially disappears, with only your specific configuration needing to
consume a linearly incremental amount of code per new type.

Code below.

regards
-Fred

class FooFactory {

  static class FooKey {
       final char type;
       final boolean inverted;

        FooKey(char type, boolean inverted) {
            this.type = type;
            this.inverted = inverted;
       }
      // ...override equals/hashCode as need be.  most likely
     // you already have this type of 'tuple' common class somewhere.
  }

  private final Map<FooKey, Provider<Foo>> providerMap;

  @Inject
  FooFactory(Map<FooKey, Provider<Foo>> providerMap) {
      this.providerMap = providerMap;
  }

  Foo get(char type, boolean inverted) {
      FooKey fooKey = new FooKey(type, inverted);
       //
http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Preconditions.html
      Provider<Foo> fooProvider =
          com.google.common.base.Preconditions.checkNotNull(
              providerMap.get(fooKey, "No provider found for key: %s",
fooKey));

      return fooProvider.get();
    }
}


* * *

in your module, simply bind your classes:

public FooModule extends AbstractModule {

   @Override
   protected void configure() {
        bind(FooFactory.class).in(Singleton.class);
        addFooBinding('A', TypeAFoo.class);
        addFooBinding('B', TypeBFoo.class);
        addInvertableFooBinding('C', true, TypeCAFoo.class);
        addInvertableFooBinding('C', false, TypeCBFoo.class);
       .... etc
   }

   private addFooBinding(Char type, Class<? extends Foo> fooClass) {
        addInvertableFooBinding(type, true, fooClass);
        addInvertableFooBinding(type, false, fooClass);
   }

   private addInvertableFooBinding(Char type, Boolean inverted, Class<?
extends Foo> fooClass) {
       FooKey fooKey = new FooKey(type, inverted);
        //
http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/multibindings/MapBinder.html
       MapBinder<FooKey, Foo> mapBinder =
           MapBinder.newMapBinder(binder(), FooKey.clas, Foo.class);
        mapBinder.addBinding(fooKey, fooClass);
    }
}



On Wed, Mar 17, 2010 at 11:57 PM, Jason Felice <[email protected]>wrote:

> I just posted this blog article:
>
> http://eraserhead.net/2010/03/creating-boilerplate-with-google-guice/
>
> A note:  While it seems to be a peculiar problem, I'm not slamming Guice,
> Guice is still a big net win for us!
>
> I post here for thoughts on this problem, and suggestions for solutions to
> it.
>
> Excerpt:
>
> There’s plenty of boilerplate that Guice removes, mostly in the “bean
> wiring” category, and this is good. Interestingly, there are areas in which
> I’ve found myself writing *more* boilerplate with Guice, and an instance
> of this is what I’d like to discuss today.
>
> I work with some people who have become thoroughly disgusted with OOP and
> advocate for functional style with immutable data types. I appreciate
> functional style with immutable data types, but I must say that the Strategy
> pattern <http://en.wikipedia.org/wiki/Strategy_pattern> is something OOP
> does well and not something that FP does nearly as well. I tend to use
> strategy pattern quite a bit in our XPay (and in our C++ product, DAS). One
> reason to prefer Strategy pattern to switch 
> statements<http://c2.com/cgi/wiki?SwitchStatementsSmell>is to have a single 
> point of control over
> *which* strategy implementation to use. This use case usually conjures
> itself into being in a Factory method 
> pattern<http://en.wikipedia.org/wiki/Factory_method_pattern>which has the 
> single switch statement which provides an instance of the
> concrete type based on input parameters.
>
> In Guice, you can inject a Provider<Foo> and Guice will automatically
> create a type that produces instances of Foo. This is useful for
> dependencies. So our factory ends up looking something like this:
>
> class FooFactory {
>
>
>     private final Provider<TypeAFoo> typeAFooProvider;
>
>     private final Provider<TypeBFoo> typeBFooProvider;
>
>     private final Provider<TypeCAFoo> typeCAFooProvider;
>
>     private final Provider<TypeCBFoo> typeCBFooProvider;
>
>     private final Provider<TypeDFoo> typeDFooProvider;
>
>     private final Provider<TypeEFoo> typeEFooProvider;
>
>
>     @Inject
>     public FooFactory(
>             final Provider<TypeAFoo> typeAFooProvider,
>
>             final Provider<TypeBFoo> typeBFooProvider,
>             final Provider<TypeCAFoo> typeCAFooProvider,
>
>             final Provider<TypeCBFoo> typeCBFooProvider,
>             final Provider<TypeDFoo> typeDFooProvider,
>
>             final Provider<TypeEFoo> typeEFooProvider
>             )
>
>     {
>         this.typeAFooProvider = typeAFooProvider;
>
>         this.typeBFooProvider = typeBFooProvider;
>
>         this.typeCAFooProvider = typeCAFooProvider;
>
>         this.typeCBFooProvider = typeCBFooProvider;
>
>         this.typeDFooProvider = typeDFooProvider;
>
>         this.typeEFooProvider = typeEFooProvider;
>
>     }
>
>     public Foo get(char type, boolean inverted) {
>
>         switch (type) {
>         case 'A':
>
>             return typeAFooProvider.get();
>
>         case 'B':
>             return typeBFooProvider.get();
>
>         case 'C':
>             if (inverted)
>
>                 return typeCAFooProvider.get();
>
>             else
>                 return typeCBFooProvider.get();
>
>         case 'D':
>             return typeBFooProvider.get();
>
>         case 'E':
>             return typeBFooProvider.get();
>
>         default:
>             throw new FooFactoryException("Can't determine type.");
>
>         }
>     }
> };
>
> Ugh!
>
> This is “better” boilerplate than the bean wiring before in that it hints
> that we might be able to concoct a general solution; however, I haven’t yet
> found it. One solution which I’ve rejected is the “injecting an injector”
> solution:
>
> class FooFactory {
>
>
>     private final Injector injector;
>
>     @Inject
>
>     public FooFactory(final Injector injector) {
>
>          this.injector = injector;
>
>     }
>     public Foo get(char type, boolean inverted) {
>
>         switch (type) {
>         case 'A':
>
>             return injector.createInstance(TypeAFoo.class);
>
>         case 'B':
>             return injector.createInstance(TypeBFoo.class);
>
>         case 'C':
>             if (inverted)
>
>                 return injector.createInstance(TypeCAFoo.class);
>
>             else
>                 return injector.createInstance(TypeCBFoo.class);
>
>         case 'D':
>             return injector.createInstance(TypeDFoo.class);
>
>         case 'E':
>             return injector.createInstance(TypeEFoo.class);
>
>         default:
>             throw new FooFactoryException("Can't determine type.");
>
>         }
>     }
> };
>
> The reason I’ve rejected this approach is that it prevents Guice from
> checking the entire dependency graph at boot – Guice doesn’t know which
> types you are going to create with the injector, and this *has* to defeat
> a lot of it’s validation magic.
>
>  --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-guice%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en.

Reply via email to