如何实现“机器人腿” Google Guice使用案例? [英] How to implement the "robot legs" use case with Google Guice?

查看:116
本文介绍了如何实现“机器人腿” Google Guice使用案例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



让我们说一些类叫服务

  @Singleton 
public class Service {
@Inject
源代码;

}

界面有两个实现:

  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)
服务服务

@Inject @SomeAnnotation(file-system)
服务serviceWithAFileSystemSource;

}

确实存在一些注释或绑定,让我注释一个成员,如 serviceWithADatabaseSource ,这有助于Guice知道内部成员 source 应该注入 SourceDatabase 实现?



编辑:感谢丹尼尔·马丁,给我们名字

解决方案

As ,您需要安装两个 PrivateModule s,每个都公开一个带有正确注释的服务。

  public class MyModule extends AbstractModu le {
@Override
protected void configure(){
install(new PrivateModule(){
@Override public void configure(){
//将源绑定到SourceDatabase。
bind(Source.class).to(SourceDatabase.class);
//绑定@Named(数据库)服务到服务。
bind(Service.class).annotatedWith(Names.named(database))
.to(Service.class);
//现在公开@Named(数据库)服务,而不暴露
//其他两个冲突的绑定之一。
exposed(Service.class).annotatedWith(Names.named(database));
}
});
install(new PrivateModule(){
@Override public void configure(){
//同上。
bind(Source.class).to(SourceFileSystem.class) ;
bind(Service.class).annotatedWith(Names.named(file-system))
.to(Service.class);
exposed(Service.class).annotatedWith( Names.named(file-system));
}
});
}
}

如果模块不是PrivateModule实例,那么绑定到来源和服务将相互冲突。但是,相反,每个绑定继承自Injector的所有公共绑定,但只将 @Named(...)Service 暴露给外部世界。这样,相同的服务实现可以注入同样的未注释的,但是它会返回不同的完全注入类型。



另请注意,您将无法要求来源服务(没有注释)在PrivateModules之外,因为您没有在任何非私有模块中建立绑定。这应该是预期的:PrivateModule绑定不应该与任何公共绑定冲突,并且没有通过PrivateModule的一个暴露的绑定进入,Guice不会知道哪个 Source 服务返回。



最后,考虑到Module实例可以获取构造函数参数,可能是一个好主意将两个匿名内部PrivateModules转换为等效的命名:

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


I'm learning Google Guice. Do you know how to implement the "robot legs" problem? Let me explain this with an example.

Let's say that I have some class called Service:

@Singleton
public class Service {
    @Inject
    Source source;

}

The interface Source has two implementations:

public class SourceDatabase implements Source {

}

public class SourceFileSystem implements Source {

}

My module is implemented like this:

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

Well, I would like to know if this is possible:

public class MainClass {    

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

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

}

Does exist some annotation or binding that let me do that, let me annotate a member like serviceWithADatabaseSource, and this helps Guice to know that the internal member source should be injected with the SourceDatabase implementation?

Edit: Thanks to Daniel Martin, for give us the name of this kind of problem on his comment.

解决方案

As documented in the Guice Wiki, you need to install two PrivateModules, each of which exposes a Service with the right annotation for you.

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

If the modules were not PrivateModule instances, those bindings to Source and Service would conflict with one another. However, instead, each binding inherits all the public bindings from the Injector but only exposes the @Named(...) Service to the outside world. This way the same Service implementation can inject the same non-annotated Source but have it return different fully-injected types.

Also note that you will not be able to ask for a Source or Service (without an annotation) outside of the PrivateModules, because you haven't established a binding in any non-private Module. This should be expected: The PrivateModule bindings shouldn't conflict with any public bindings, and without entering through one of the PrivateModule's exposed bindings, Guice won't know which Source or Service to return.

Finally, given that Module instances can take constructor parameters, it may be a good idea to extract the two anonymous inner PrivateModules into a named equivalent:

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

这篇关于如何实现“机器人腿” Google Guice使用案例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆