如何使用Guice AssistedInject与接口的多个实现?

时间:2014-12-12 11:08:44

标签: java guice factory assisted-inject

我无法找到如何拥有“动态AssistedInject”。 我的意思是,我想向工厂提供它需要在运行时根据参数使用的实现类名。 这是我现在拥有的:

interface Letter {}

abstract class ALetter implements Letter {
    public ALetter(T1 t1, T2 t2) {...} 
}

class A implements Letter {
    public static final NAME = "A";

    @Inject
    public A(@Assisted T1 t1, T2 t2) { super(t1, t2); }
}

class B implements Letter {
    public static final NAME = "B";

    @Inject
    public B(@Assisted T1 t1, T2 t2) { super(t1, t2); }
}

我希望能够根据他们的名字加载A或B,考虑到我会有T1,但我需要注入T2。 它可能看起来像:

class MyClass {
    @Inject
    public MyClass(RequestData data, MyConfig config, ILetterFactory letterFactory) {
        Letter letter = letterFactory.get(data.getLetterName(), config.getT2());
    }
}

我会使用类似的东西配置ILetterFactory:

install(new FactoryModuleBuilder().build(ILetterFactory.class));

但是我知道这当前不会起作用,因为lettername不是我的构造函数的真正参数,而Guice就是不能那样工作。它应该让你知道我想要的东西。

我目前找到的唯一解决方案是不使用Guice:我有自己的工厂,根据名称解析类构造函数(通过Map<String, Constructor>),并调用newInstance提供它适当的参数(除了工厂本身之外根本没有注射)。

有没有办法使用Guice来避免自己创建该工厂? 感谢

1 个答案:

答案 0 :(得分:1)

FactoryModuleBuilder没有您想象的那么强大 - 它没有在实现之间切换的规定,并且仅用于将注入的依赖项与其他构造函数参数混合。幸运的是,Guice使您的工厂易于编写。你正在寻找的是这个界面的实现:

public interface ILetterFactory {
  /** This assumes that T2 is a Guice-satisfied dependency,
    * and not meant to be @Assisted, so leave it out of the interface. */
  Letter get(String which);
}

选择一个是让Guice为您的实例提供一个Provider,如果你的Letters有很多不同的deps,或者你的deps列表很长或经常更改,那么这个最有用。如果A和B需要辅助依赖项,请将Provider<A>替换为您通过FactoryModuleBuilder绑定的A.Factory

public class LetterFactory implements ILetterFactory {
  @Inject Provider<A> aProvider;
  @Inject Provider<B> bProvider;

  @Override public Letter get(String which) {
    if (A.NAME.equals(which)) {
      return aProvider.get();
    } else if (B.NAME.equals(which)) {
      return bProvider.get();
    } else {
      throw new IllegalArgumentException("Letter does not exist");
    }
  }
}

选择二,你负责从Guice创建一个新实例。如果你的deps列表发生变化,它需要更多的维护,并且不能很好地与AOP和其他类似的功能一起使用,但如果你的Letters需要辅助参数和一小组类似的deps,可能会少一些工作:

public class LetterFactory implements ILetterFactory {
  @Inject Provider<T2> t2Provider;

  @Override public Letter get(String which) {
    if (A.NAME.equals(which)) {
      return new A(t2Provider.get());
    } else if (B.NAME.equals(which)) {
      return new B(t2Provider.get());
    } else {
      throw new IllegalArgumentException("Letter does not exist");
    }
  }
}