2016-03-03 24 views
2

我正在学Google Guice。你知道如何实现“机器人腿”问题吗?让我用一个例子来解释一下。如何在Google Guice中实现“机器人腿”用例?

比方说,我有一些类称为Service

@Singleton 
public class Service { 
    @Inject 
    Source source; 

} 

接口Source有两种实现方式:

public class SourceDatabase implements Source { 

} 

public class SourceFileSystem implements Source { 

} 

我的模块,像这样实现的:

public class MyModule extends AbstractModule { 
    @Override 
    protected void configure() { 
     bind(Service.class).asEagerSingleton(); 
    } 
} 

好,我想知道这是否可能:

public class MainClass {  

    @Inject @SomeAnnotation("database") 
    Service serviceWithADatabaseSource; 

    @Inject @SomeAnnotation("file-system") 
    Service serviceWithAFileSystemSource; 

} 

确实存在一些注释或绑定,让我做到这一点,让我像注释一serviceWithADatabaseSource成员,这有助于吉斯知道内部成员source应与SourceDatabase执行注射?

编辑:感谢Daniel Martin,在他的评论中给我们提出了这类问题的名称。

+2

https://github.com/google/guice/wiki/FrequentlyAskedQuestions#how-do-i-build-two-similar-but-slightly-different-trees-of-objects(你描述的是“机器人腿”问题) –

回答

3

由于documented in the Guice Wiki,您需要安装两个PrivateModule s,其中每个都会为您提供正确的注释。

public class MyModule extends AbstractModule { 
    @Override 
    protected void configure() { 
    install(new PrivateModule() { 
     @Override public void configure() { 
     // Bind Source to SourceDatabase. 
     bind(Source.class).to(SourceDatabase.class); 
     // Bind @Named("database") Service to Service. 
     bind(Service.class).annotatedWith(Names.named("database")) 
      .to(Service.class); 
     // Now expose @Named("database") Service without exposing 
     // either of the other two conflicting bindings. 
     expose(Service.class).annotatedWith(Names.named("database")); 
     } 
    }); 
    install(new PrivateModule() { 
     @Override public void configure() { 
     // Same as above. 
     bind(Source.class).to(SourceFileSystem.class); 
     bind(Service.class).annotatedWith(Names.named("file-system")) 
      .to(Service.class); 
     expose(Service.class).annotatedWith(Names.named("file-system")); 
     } 
    }); 
    } 
} 

如果模块不是PrivateModule实例,那些绑定到Source和Service的绑定将会相互冲突。但是,每个绑定继承了Injector的所有公共绑定,但仅向外界公开@Named(...) Service。这样,相同的Service实现可以注入相同的未注释的Source,但它会返回不同的完全注入类型。

另请注意,由于尚未在任何非私有模块中建立绑定,您将无法在PrivateModules外部请求SourceService(没有注释)。这应该是预料之中的:PrivateModule绑定不应该与任何公共绑定冲突,并且不通过PrivateModule的一个公开绑定输入,Guice将不知道要返回哪个SourceService

最后,考虑到模块实例可以采取构造函数的参数,它可能是一个好主意,两个匿名内部PrivateModules提取到一个名为相当于:

public class MyModule extends AbstractModule { 
    @Override 
    protected void configure() { 
    install(new SourcePrivateModule(SourceDatabase.class, "database")); 
    install(new SourcePrivateModule(SourceFileSystem.class, "file-system")); 
    } 
}