如何使用Guice的AssistedInject工厂和服务加载器?

时间:2016-07-18 06:44:22

标签: java dependency-injection guice guice-3

在我的guice模块中,我有多个工厂,如下所示:

install(new FactoryModuleBuilder().implement(SportsCar.class,Ferrari.class).build(FerrariFactory.class));
install(new FactoryModuleBuilder().implement(LuxuryCar.class,Mercedes.class).build(MercedesFactory.class));

两个工厂都有以下创建方法,它采用辅助元素:

Ferrari create(@Assisted Element partsElement);

Mercedescreate(@Assisted Element partsElement);

在CarChooser课程中,我得到了法拉利或梅赛德斯的实例,如下所示:

@Inject 
public CarChooser(FerrariFactory ferrariFactory , MercedesFactory mercedesFactory )
{
        this.ferrariFactory = ferrariFactory;
        this.mercedesFactory = mercedesFactory;
} 

在同一个班级:

if(type.equals("ferrari"))
    ferrariFactory.create(partsElement);
else if (type.equals("mercedes"))
    mercedesFactory.create(partsElement);
.....
......

现在,我正在尝试的是将此CarChooser类打开以进行扩展,但关闭以进行修改。即如果我需要添加另一个Factory,我不应该将它声明为变量+将其添加到构造函数+为相应的新类型添加另一个if子句。我打算在这里使用ServiceLoader并声明一个接口CarFactory将由所有工厂(如FerrariFactory,MercedesFactory等)实现,所有实现都将有一个getCarType方法。但是如何使用Service Loader调用create方法?

ServiceLoader<CarFactory> impl = ServiceLoader.load(CarFactory.class);

        for (CarFactory fac: impl) {
            if(type.equals(fac.getCarType()))
               fac.create(partsElement);
        }

如果它正常工作是正确的方式(我甚至不确定这是否有效)。或者有更好的方法吗?

感谢帖子的第一条评论,我知道我想使用MapBinder。我写了一个CarFactory,由FerrariFactory和MercedesFactory扩展。所以我添加以下内容:

    MapBinder<String, CarFactory> mapbinder = MapBinder.newMapBinder(binder(), String.class, CarFactory.class);

   mapbinder.addBinding("Ferrari").to(FerrariFactory.class);
   mapbinder.addBinding("Mercedes").to(MercedesFactory.class);

但是由于上面代码的.to部分是抽象类,我得到一个初始化错误,FerrariFactory没有绑定到任何实现。我应该在这里将它绑定到使用FactoryModuleBuilder声明的正确的Assisted Inject Factory?

1 个答案:

答案 0 :(得分:0)

因此,使用MapBinder和泛型是解决方案。

    install(new FactoryModuleBuilder().implement(SportsCar.class,Ferrari.class).build(FerrariFactory.class));
    install(new FactoryModuleBuilder().implement(LuxuryCar.class,Mercedes.class).build(MercedesFactory.class));



    MapBinder<String, CarFactory<?>> mapbinder = MapBinder.newMapBinder(binder(), new TypeLiteral<String>(){}, new TypeLiteral<CarFactory<?>>(){});

     mapbinder.addBinding("ferrari").to(FerrariFactory.class);  
     mapbinder.addBinding("mercedes").to(MercedesFactory.class);

这里需要注意的重要一点是,这似乎只在Guice 3.0 + JDK 7中得到支持。对于JDK 8,你需要Guice 4.0!在https://github.com/google/guice/issues/904

上发现了此问题

希望有所帮助。

有关解决方案的更多细节:

http://crusaderpyro.blogspot.sg/2016/07/google-guice-how-to-use-mapbinder.html