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].
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en.

Reply via email to