2

我很难找到如何拥有“动态 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); }
}

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

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));

但我知道这目前不起作用,因为字母名称不是我的构造函数的真正参数,而 Guice 不能那样工作。它应该让你知道我想要什么。

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

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

4

1 回答 1

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,如果您的 Letter 具有广泛不同的 deps,或者如果您的 deps 列表很长或经常更改,这将是最有用的。如果 A 和 B 需要辅助依赖,请替换Provider<A>A.Factory您通过 FactoryModuleBuilder 绑定的。

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");
    }
  }
}
于 2014-12-12T23:43:50.800 回答