如何将引用模块中字段的匿名提供者移动到单独的类中?

Posted

技术标签:

【中文标题】如何将引用模块中字段的匿名提供者移动到单独的类中?【英文标题】:How to move an anonymous Provider that references fields in the module into a separate class? 【发布时间】:2017-02-03 00:59:41 【问题描述】:

玩具示例:

public class MyModule extends AbstractModule 
  private static final Foo foo;

  public MyModule(Foo foo) 
    this.foo = foo;
  

  @Override
  public void configure() 
    bind(Bar.class).toProvider(new Provider<Bar>() 
      @Override public Bar get() 
        return foo.getBar();
      
    );
  

这让我可以懒惰地调用存储在MyModule 字段中的用户提供的Foo 实例的.getBar() 方法。但是现在provider has its own dependencies - 因此我需要定义一个非匿名类,我指定了一个@Inject 构造函数。比如:

public class MyModule extends AbstractModule 
  private static final Foo foo;

  public MyModule(Foo foo) 
    this.foo = foo;
  

  @Override
  public void configure() 
    bind(Bar.class).toProvider(BarProvider.class);
  

  BarProvider implements Provider<Bar> 
    private Baz baz;

    @Inject BarProvider(Baz baz) 
      this.baz = baz;
    

    @Override public Bar get() 
      return foo.getBar(baz);
    
  

完美!除了Guice doesn't like this...

线程“main”com.google.inject.CreationException 中的异常:无法创建注入器,请参阅以下错误:

1) 不支持注入内部类。请使用“静态”类(***或嵌套)而不是 com.example.MyModule$BarProvider。

所以,我陷入了困境。我需要同时访问模块上的字段和来自Provider 类的注入类型。有没有办法做到这一点?


注意:这个玩具示例排除了一些实际的复杂性——尤其是bind() 语句涉及更多,这就是为什么我不能简单地定义一个@Provides 方法。

【问题讨论】:

【参考方案1】:

在某种程度上,注入内部类是不可能的,因为 Guice 无法在没有外部父实例的情况下反射地创建内部实例(相当于神秘的 outerInstance.new InnerInstance() 语法)。

一些选项:

使 Foo 可通过您的图表进行注入,可能隐藏在 PrivateModule 中,因此它不会暴露在您的整个图表中(如果这对您很重要的话)。 使用匿名的内部 Provider(或提取的等价物),并从 AbstractModule 的 getProvider(Class&lt;T&gt;) 方法中获取 Provider&lt;Baz&gt;。如果您尝试在创建 Injector 之前调用它,您会得到一个异常,但是对于您正在做的方式创建一个 Provider,这可能不是问题。 在玩具问题之外发布您的bind,看看@Provides 是否可以通过一些聪明才智来实现。

相关:Accessing Guice injector in its Module?

【讨论】:

谢谢杰夫!发布后我意识到我需要的是getProvider()。它正盯着我的脸,但由于某种原因它没有点击:)【参考方案2】:

我意识到让 Guice 为我构建我的 Provider 让我感到厌烦,而我实际上并不需要这样做。尽管 Guice 文档中的示例传递了 DatabaseTransactionLogProvider.class ,但与第一个 sn-p 更好的并行将是手动构造我的 Provider 的实例,并同时传递 Foo 实例和 Provider&lt;Baz&gt; 实例( provided by the module)。

public class MyModule extends AbstractModule 
  private static final Foo foo;

  public MyModule(Foo foo) 
    this.foo = foo;
  

  @Override
  public void configure() 
    bind(Bar.class).toProvider(new BarProvider(foo, getProvider(Baz.class));
  

  static BarProvider implements Provider<Bar> 
    private final Foo foo;
    private final Provider<Baz> bazProvider;

    BarProvider(Foo foo, Provider<Baz> bazProvider) 
      this.foo = foo;
      this.bazProvider = bazProvider;
    

    @Override public Bar get() 
      return foo.getBar(bazProvider.get());
    
  

【讨论】:

以上是关于如何将引用模块中字段的匿名提供者移动到单独的类中?的主要内容,如果未能解决你的问题,请参考以下文章

UITableView - 从单独的类中重新加载数据

浅谈Perl的类包模块与面对对象编程

如何将 View 类中的代码片段移动到 OnAppearing() 方法?

使用匿名函数进行PHPUnit测试

OpenGL 帧缓冲函数不能在单独的类中完全工作

如何将一个模块内的类中的 pyqtSignal 连接到另一个模块内的类中的 pyqtSlot?