具有逻辑的 Guice AssistedInjection Factory

Guice AssistedInjection Factory with logic

我一直在为一个项目使用 guice。

我有一个抽象 class,它有很多实现。为了使用正确的实现,我使用了一个接收参数的工厂,然后 returns 正确的实例。

演示代码

@Singleton
public class MyFactory {

    private final Foo foo;

    @Inject
    public MyFactory(final Foo foo) {
        this.foo = foo;
    }

    public A create(final Bar bar) {
        switch (bar) {
            case 0:
                return new B(foo, bar);
            case 1:
                return new C(foo, bar);
            //this goes on
        }
    }
}

public abstract A {
    public A(final Bar bar) {
        //do sth
    }
}

public B extends A {
    private final Foo foo;

    public B(final Foo foo, final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

public C extends A {
    private final Foo foo;

    public C(final Foo foo, final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

我想知道的是,如果我可以用Guice替换工厂直接注入A的实现(注意他们应该使用辅助注入)?

谢谢。

You will still need MyFactory to choose an implementation based on your id, though your assisted injection can be very short.

// No need for this to be @Singleton;
// if you want the same shared Foo instance, make it @Singleton
public class MyFactory {

    private final B.Factory bFactory;
    private final C.Factory cFactory;

    @Inject
    public MyFactory(B.Factory bFactory, C.Factory cFactory) {
        this.bFactory = bFactory;
        this.cFactory = cFactory;
    }

    public A create(final Bar bar) {
        switch (bar.getSomeInteger()) {   // I assume you're checking a
                                          // property of bar
            case 0:
                return bFactory.create(bar);
            case 1:
                return cFactory.create(bar);
            //this goes on
        }
    }
}

public B extends A {
    public interface Factory {
        B create(Bar bar);
    }

    private final Foo foo;

    public B(final Foo foo, @Assisted final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

public C extends A {
    public interface Factory {
        C create(Bar bar);
    }

    private final Foo foo;

    public C(final Foo foo, @Assisted final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

你的模块:

public class YourModule extends AbstractModule {
  @Override public void configure() {
    install(new FactoryModuleBuilder().build(B.Factory.class));
    install(new FactoryModuleBuilder().build(C.Factory.class));
  }
}

编辑: 在我的示例中,您 不需要 调用 FactoryModuleBuilder 上的 implement,因为 B.Factory 有一个 create 方法 return 是你的子类 B。如果你想 return 你的超类 A 的方法,隐藏具体类型,你可以这样做;那么您将需要 implement 调用,因为 Guice 不知道要尝试调用哪个构造函数。

如果您想强制消费者对实现进行编码,您可能需要引用仅 return 接口的工厂。 隐藏实现细节 通常是个好主意,并且可能涉及使用方法 A create(Bar bar) 创建 A.Factory 并将其与 implement 连接起来.但是,这里是不必要的,因为您的 MyFactory 已经 returns A 并隐藏了实现子类(在逻辑上表现得像 A.Factory),并且因为您需要 @Named 或其他一些限定符注释来区分您正在创建的两个 A.Factory 绑定。简而言之,这是额外的并发症,对这种特定情况没有任何好处。