运行时基于carType通过Guice获取实例,能否省略工厂类?
当然可以!Guice本身就提供了优雅的方式帮你省去手动编写工厂类的麻烦,直接根据carType动态获取对应的Car实例,下面给你介绍两种常用的方案:
方案一:使用Guice的MapBinder(推荐)
这是Guice官方推荐的处理“键值对绑定”的方案,专门用来解决这种根据标识获取不同实现的场景,完全能替代你手写的CarFactory。
步骤1:配置Module,绑定Car的实现到对应类型
首先创建一个Guice Module,用MapBinder把每个Car子类和对应的carType字符串绑定起来:
import com.google.inject.AbstractModule; import com.google.inject.multibindings.MapBinder; public class CarModule extends AbstractModule { @Override protected void configure() { // 创建MapBinder,键是String类型(carType),值是Car类型 MapBinder<String, Car> carMapBinder = MapBinder.newMapBinder(binder(), String.class, Car.class); // 绑定具体的实现类到对应的类型字符串 carMapBinder.addBinding("twoWheeler").to(TwoWheeler.class); carMapBinder.addBinding("fourWheeler").to(FourWheeler.class); } }
步骤2:在RandomClass中直接注入Map
接下来修改RandomClass,不需要再注入CarFactory,直接注入Guice自动生成的Map<String, Car>(或者Map<String, Provider<Car>>,看你是否需要每次获取新实例):
如果Car实例是单例(每次获取同一个实例):
import com.google.inject.Inject; import java.util.Map; public class RandomClass { private final Map<String, Car> carMap; // Guice会自动把我们绑定的所有Car实现填充到这个Map里 @Inject public RandomClass(Map<String, Car> carMap) { this.carMap = carMap; } void doSomething(String carType) { Car car = carMap.get(carType); // 在这里使用car实例即可 } }
如果需要每次获取新的Car实例(非单例场景):
注入Map<String, Provider<Car>>,通过Provider.get()来获取新实例:
import com.google.inject.Inject; import com.google.inject.Provider; import java.util.Map; public class RandomClass { private final Map<String, Provider<Car>> carProviderMap; @Inject public RandomClass(Map<String, Provider<Car>> carProviderMap) { this.carProviderMap = carProviderMap; } void doSomething(String carType) { Provider<Car> carProvider = carProviderMap.get(carType); Car car = carProvider.get(); // 每次调用get()都会生成新实例(取决于你绑定的Scope) } }
方案二:使用@Named注解(适合类型较少的场景)
如果你的Car子类数量不多,也可以用@Named注解来标识不同的实现,不过这种方式不如MapBinder灵活,而且直接用Injector的话是反模式,不推荐在业务代码中使用。
步骤1:配置Module绑定带@Named的Car实现
import com.google.inject.AbstractModule; import com.google.inject.name.Names; public class CarModule extends AbstractModule { @Override protected void configure() { bind(Car.class).annotatedWith(Names.named("twoWheeler")).to(TwoWheeler.class); bind(Car.class).annotatedWith(Names.named("fourWheeler")).to(FourWheeler.class); } }
步骤2:通过Injector获取实例(不推荐)
你可以在RandomClass中注入Injector,然后根据@Named的标识获取实例,但这种方式会让你的代码直接依赖Guice的Injector,降低了代码的可测试性和独立性:
import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.name.Names; public class RandomClass { private final Injector injector; @Inject public RandomClass(Injector injector) { this.injector = injector; } void doSomething(String carType) { Car car = injector.getInstance(Key.get(Car.class, Names.named(carType))); } }
总结
优先选择MapBinder方案,它既保持了依赖注入的优势,又完全替代了手写工厂类的工作,代码更简洁、可维护性更高。
内容的提问来源于stack exchange,提问作者user93796
相关产品推荐
相关产品推荐

