Java Guice 3-使用辅助注入时自动构建对象图

Java Guice 3-使用辅助注入时自动构建对象图,java,dependency-injection,guice,Java,Dependency Injection,Guice,我感兴趣的是,如何正确地构造具有依赖项的对象,这些依赖项本身具有@Assisted参数。一个例子将更好地说明: 通常,对于没有@Assisted参数的依赖项,您可以简单地拥有对象的复杂继承权,这些对象都有它们的依赖项,并且这些依赖项被注入。没问题,我可以只获取一个对象的实例,它的所有依赖项都将被生成并注入,而无需我做任何事情 但是,如果我想更改它,使对象层次结构中的某些依赖项具有@Assisted参数,那么我必须自己使用工厂ie创建这些实例: public SomeConcreteService

我感兴趣的是,如何正确地构造具有依赖项的对象,这些依赖项本身具有@Assisted参数。一个例子将更好地说明:

通常,对于没有
@Assisted
参数的依赖项,您可以简单地拥有对象的复杂继承权,这些对象都有它们的依赖项,并且这些依赖项被注入。没问题,我可以只获取一个对象的实例,它的所有依赖项都将被生成并注入,而无需我做任何事情

但是,如果我想更改它,使对象层次结构中的某些依赖项具有
@Assisted
参数,那么我必须自己使用工厂ie创建这些实例:

public SomeConcreteService(@Assisted String string) {
    this.string = string;
}

MyFactory myFactory = injector.getInstance(MyFactory .class);
SomeService myService = factory.getMyService("some string");
这将导致对象的干净实例化出现问题,因为我必须手动创建这些实例。并将它们传递到所需的对象中,这基本上使该对象的DI变得冗余,我认为????ie然后我需要使用
new
关键字并手动传递所有依赖项

new MyComplexObject(myService, myOtherService)

如果一个或多个依赖项使用
@Assisted
参数,我如何使其不必手动构建对象图?

您需要问自己的问题是,“为什么我要创建这个
@Assisted
,谁将创建这些对象?”

如果您使用该键获取所需的实例,那么您所拥有的一切都很好:

public class YourInjectableClass {
  @Inject private MyFactory factory;

  public void doStuff(String key) {
    // You have a key, and your factory, so you can create the instance yourself.
    SomeService service = factory.getMyService(key);
    // [...]
  }
}
但是,如果您使用该键获取一个实例创建一个实例来创建一个实例以获取所需的内容,那么这似乎是有问题的。这可能是一个更好的问题:

因为整个依赖关系树都需要您的值,所以您可以将其视为注入依赖关系。这可能会有点混乱,但可以避免让依赖关系一直关注实例化细节

或者,您可以创建手动OuterObjectFactory facade,该facade会手动调用
new
。对于遗留代码来说,这可能是一个更好的解决方案,但通过确保一个类负责抽象实例化细节,可以帮助遵循单一责任原则



注意:我假设
SomeConcreteService
采用对象图可以提供的其他依赖项。如果没有,那么就根本没有理由使用注入:给SomeConcreteService一个公共构造函数,并在需要的地方调用
new SomeConcreteService(“此处的值”)
。尽管Guice费尽心思抽象出
new
的使用,但也没有必要创建数据对象或依赖项轻对象,如
HashMap
Date

我实际上没有实际场景,我只是在考虑它。但是,即使
SomeConcreteService
不需要其他依赖项,如果它可以(例如)切换到另一个服务,那么使用Guice管理它可能仍然是好的;只是想一想。关于你的回答,我认为大多数时候你的第一个例子就足够了。主要的变化是:注入工厂并使用一些基本上
init()
方法来初始化依赖项(我假设它会在整个类中使用多次),或者如果只使用一次,那么
doStuff()
方法就足够了。因此,我需要添加额外的逻辑来传递您所说的密钥,这是可以理解的。你的第二个例子,但我不认为我完全理解,但我会花一些时间来研究:)
public class YourInjectableClass {
  @Inject private Injector injector;
  public void doStuff(String key) {
    // You need an OuterObject. So rather than calling
    // new OuterObject(new InnerObject(factory.getMyService(key))), do:
    OuterObject outerObject =
        injector.createChildInjector(new OuterObjectModule(key))
        .getInstance(OuterObject.class);
    // [...]
  }
}