【问题标题】:Guice AssistedInjection Factory with logic具有逻辑的 Guice AssistedInjection Factory
【发布时间】:2018-06-12 00:00:26
【问题描述】:

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

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

演示代码

@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的实现(注意他们应该使用辅助注入)?

谢谢。

【问题讨论】:

    标签: java guice


    【解决方案1】:

    You will still need MyFactory 根据您的id 选择实现,尽管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 有一个返回您的子类B 的create 方法. 如果您希望该方法返回您的超类 A,隐藏具体类型,您可以这样做;那么你需要implement 调用,因为Guice 不知道要尝试调用哪个构造函数。

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

    【讨论】:

    • 那么 guice 没有办法帮助我摆脱那个工厂,因为它有逻辑吗?并感谢您的回复。顺便说一句,你为什么不让工厂单例?
    • 您可以使用Multibindings,但是您需要以一种或另一种方式表示从int 到A 的映射,而Guice 无法为您推断出该映射。而且,如果您制作 Factory Singleton,它将永远不会被垃圾收集(更多内存)并且将在其创建过程中同步(同步开销),这样您就可以保证获得相同的实例。在桌面虚拟机上,新对象很便宜;如果您不需要它是同一个对象,则需要速度和内存。
    • 很抱歉问了很多问题,但我还有一个问题:模块安装不应该是这样的: install(new FactoryModuleBuilder.implement(A.class, B.class).build(B .Factory.class));
    • 非常感谢
    猜你喜欢
    • 2018-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    • 2019-02-08
    • 2018-06-02
    • 2020-03-07
    • 1970-01-01
    相关资源
    最近更新 更多