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.