Factory and Abstract Factory patterns using Guice

2,323 views
Skip to first unread message

egolan

unread,
Dec 28, 2011, 3:47:46 PM12/28/11
to google-guice
Hi,
Our whole project uses hand-written DI and I really want to switch to
Guice.
Here's something we have and I would like to understand how it's done
with Guice.

we have a factory method, that based on an input string, returns a
specific implementation of an Abstract Factory:

public class TypeFactoryCreator {
public static AggregationStrategyHolder
createStrategyHolder(IConfiguration configuration, Date toDate) {

switch (enum based on a string) {
...
}

AggregationStrategyHolder has two members (strategy and abstract
factory):
public class AggregationStrategyHolder {
private final AggregationStrategy aggregationStrategy;
private final AggregationFactory aggregationFactory;
...
}

So, the factory method builds the strategy and AggregationFactory
based on input string.
AggregationFactory is an Abstract Factory design pattern.


So I think that my question should be, how to bind different classes
according to runtime input?

Was I clear ? :)

Thanks

Eyal

Sam Berlin

unread,
Dec 28, 2011, 4:14:38 PM12/28/11
to google...@googlegroups.com
AssistedInject does something similar.  See:  http://code.google.com/p/google-guice/wiki/AssistedInject  & the FactoryModuleBuilder javaodc @  http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html .  Rather than changing the response based on the input, though, there's a different factory methods that return the different objects.  Changing the response based on the input will necessarily require a hand-written factory (but that factory can still use Guice-injected objects, easing some of the pain).

sam


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


egolan

unread,
Dec 29, 2011, 10:53:54 AM12/29/11
to google-guice
Hi,
Thanks.

I looked into the classes you suggested.As a newbie, I might have
missed something, but I couldn't figure out how the factory module
builder can help.
However, I thought of an idea and please let me know if it is a good
practice.As you suggested, I might use hand-written factory, but this
time I am using it for building a Module.(Something similar to the
example with the Robot legs)
Here's what I came up with:I have these interfacespublic interface
AggregationStrategy {...}public interface QueueOperations {...}
The queue operation has two simple concrete classes and I won't write
them down.Here's the concrete classes of the strategy:
public abstract class AbstractStrategy implements AggregationStrategy
{    private final QueueOperations queueOperations;    public
AbstractStrategy(QueueOperations queueOperations) {       
this.queueOperations = queueOperations;    }    @Override    public
QueueOperations getQueueOperations() {        return queueOperations; 
  }}
public class TypeOneStrategy extends AbstractStrategy {    @Inject   
public TypeOneStrategy(QueueOperations queueOperations) {       
super(queueOperations);    }}
public class TypeTwoStrategy extends AbstractStrategy {    @Inject   
public TypeTwoStrategy(QueueOperations queueOperations) {       
super(queueOperations);    }}
Here are the modules:public abstract class AbstractAppModule extends
PrivateModule { // can be AbstractModule as well    public
AbstractAppModule() {    }    @Override    protected final void
configure() {        System.out.println("doing all general binding"); 
      //Here we will do all binding that are general for the whole
application        addBindings();    }    protected abstract void
addBindings();}
public class TypeOneAppModule extends AbstractAppModule {   
@Override    protected void addBindings() {       
System.out.println("binding for TypeOne");       
bind(QueueOperations.class).to(TypeOneQueueOperations.class);       
bind(AggregationStrategy.class).to(TypeOneStrategy.class);       
expose(QueueOperations.class); //just experimenting with
PrivateModule        expose(AggregationStrategy.class);    }}
public class TypeTwoAppModule extends AbstractAppModule {   
@Override    protected void addBindings() {       
System.out.println("binding for TypeTwo");       
bind(QueueOperations.class).to(TypeTwoQueueOperations.class);       
bind(AggregationStrategy.class).to(TypeTwoStrategy.class);       
expose(QueueOperations.class); //just experimenting with
PrivateModule        expose(AggregationStrategy.class);    }}
This is the hand written factory method:public class AppFactory {   
public static Module setupModule(String strategy) {       
StratgeyType stratgeyType = StratgeyType.valueOf(strategy); // an
enum        switch (stratgeyType) {        case TypeOne:           
return new TypeOneAppModule();        case TypeTwo:            return
new TypeTwoAppModule();        default:            throw new
RuntimeException(strategy);        }    }}
And here's the main method:    public static void main(String[] args)
{        System.out.println("Binding TypeOne");       
System.out.println();        Injector injector =
Guice.createInjector(AppFactory.setupModule("TypeOne"));       
AggregationStrategy strategy =
injector.getInstance(AggregationStrategy.class);       
System.out.println(strategy.getClass().getSimpleName());       
System.out.println(strategy.getQueueOperations().getClass().getSimpleName()); 
              System.out.println();        System.out.println("Binding
TypeTwo");        System.out.println();        injector =
Guice.createInjector(AppFactory.setupModule("TypeTwo"));       
strategy = injector.getInstance(AggregationStrategy.class);       
System.out.println(strategy.getClass().getSimpleName());       
System.out.println(strategy.getQueueOperations().getClass().getSimpleName()); 
  }
Well,It seems nice but a little bit smelly I think.
Any thoughts?
Thanks,
Eyal

On Dec 28, 11:14 pm, Sam Berlin <sber...@gmail.com> wrote:
> AssistedInject does something similar.  See:http://code.google.com/p/google-guice/wiki/AssistedInject & the
> FactoryModuleBuilder javaodc @http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/injec...

Jared Bunting

unread,
Dec 28, 2011, 4:43:33 PM12/28/11
to google...@googlegroups.com, Sam Berlin
I think my requirement was similar to yours so maybe my solution will
help you. I have several different implementations of an interface,
and I wanted runtime configuration to select which one to use.

interface MyInterface {}

class MyImplA implements MyInterface {}

class MyImplB implements MyInterface {}

class MyModule extends AbstractModule {
void configure() {
MapBinder<String, MyInterface> mapBinder =
MapBinder.newMapBinder(binder(), String.class, MyInterface.class);
mapBinder.addBinding("A").to(MyImplA.class);
mapBinder.addBinding("B").to(MyImplB.class);
}

@Provides
MyInterface provideMyInterface(@Named("interface.selection.key")
String key, Map<String, MyInterface> interfaceMap) {
return interfaceMap.get(key);
}
}

Obviously you can use a provider instead of the @Provides method.

And the key should be bound as a constant (in my case, it comes from a
properties file that is bound using Names.bindProperies).

You can add the implementation bindings in any module, so long as
they're exposed to the module that binds the provider.

I think I captured the intention there. In your case, I would imagine
that you would bind the IConfiguration object and access that from your
provider. Or, if your configuration changes during execution, then you
may simply want to inject that map into an object that has the
AggregationStrategyHolder createStrategyHolder(IConfiguration
configuration, Date toDate) method on it.


Let me know if I can be more clear on any points.

-Jared

> <mailto:google...@googlegroups.com>.


> To unsubscribe from this group, send email to
> google-guice...@googlegroups.com

> <mailto:google-guice%2Bunsu...@googlegroups.com>.

Reply all
Reply to author
Forward
0 new messages