如何使用Guice DI实现策略模式并注入不同策略实现类?
用Guice实现策略模式的两种方案
方案一:通过@Named注解区分策略实例
这种方式适合策略数量固定、不需要动态扩展的场景,直接在模块中绑定带命名标识的策略实现,然后在Client中注入对应实例。
1. 配置Guice模块
在自定义Module中,给两个策略实现绑定不同的@Named标识:
public class MetricModule extends AbstractModule { @Override protected void configure() { // 绑定A策略,标记为"A" bind(MetricCollectorStrategy.class) .annotatedWith(Names.named("A")) .to(AMetricCollector.class); // 绑定B策略,标记为"B" bind(MetricCollectorStrategy.class) .annotatedWith(Names.named("B")) .to(BMetricCollector.class); // 绑定MetricPublisher(如果它有依赖也会自动注入) bind(MetricPublisher.class); } }
2. 在Client类中注入策略实例
通过构造方法注入带@Named标记的两个策略实例,然后根据条件选择调用:
public class Client { private final MetricCollectorStrategy aCollector; private final MetricCollectorStrategy bCollector; @Inject public Client(@Named("A") MetricCollectorStrategy aCollector, @Named("B") MetricCollectorStrategy bCollector) { this.aCollector = aCollector; this.bCollector = bCollector; } public void processMetric(String condition) { MetricCollectorStrategy targetCollector = "useA".equals(condition) ? aCollector : bCollector; targetCollector.collectAndPublishMetric(); } }
方案二:用MapBinder管理所有策略
如果需要动态扩展策略(比如后续新增C、D策略),用MapBinder可以将所有策略统一管理在一个Map中,Client直接根据key获取对应策略,无需修改Client代码。
1. 配置Guice模块
使用MapBinder创建键值对形式的策略绑定:
public class MetricModule extends AbstractModule { @Override protected void configure() { // 创建String到MetricCollectorStrategy的MapBinder MapBinder<String, MetricCollectorStrategy> strategyMapBinder = MapBinder.newMapBinder( binder(), String.class, MetricCollectorStrategy.class); // 添加A策略,key为"A" strategyMapBinder.addBinding("A").to(AMetricCollector.class); // 添加B策略,key为"B" strategyMapBinder.addBinding("B").to(BMetricCollector.class); // 绑定MetricPublisher bind(MetricPublisher.class); } }
2. 在Client类中注入策略Map
直接注入策略Map,根据条件对应的key获取策略实例:
public class Client { private final Map<String, MetricCollectorStrategy> strategyMap; @Inject public Client(Map<String, MetricCollectorStrategy> strategyMap) { this.strategyMap = strategyMap; } public void processMetric(String strategyKey) { MetricCollectorStrategy collector = strategyMap.get(strategyKey); if (collector == null) { throw new IllegalArgumentException("未找到对应策略:" + strategyKey); } collector.collectAndPublishMetric(); } }
额外优化:懒加载策略实例
如果策略实例初始化成本较高,可以注入Provider<MetricCollectorStrategy>延迟创建实例,只有在需要时才初始化:
// 以方案一为例,修改Client的注入方式 public class Client { private final Provider<MetricCollectorStrategy> aCollectorProvider; private final Provider<MetricCollectorStrategy> bCollectorProvider; @Inject public Client(@Named("A") Provider<MetricCollectorStrategy> aCollectorProvider, @Named("B") Provider<MetricCollectorStrategy> bCollectorProvider) { this.aCollectorProvider = aCollectorProvider; this.bCollectorProvider = bCollectorProvider; } public void processMetric(String condition) { MetricCollectorStrategy collector = "useA".equals(condition) ? aCollectorProvider.get() : bCollectorProvider.get(); collector.collectAndPublishMetric(); } }
内容的提问来源于stack exchange,提问作者Arpan Das
相关产品推荐
相关产品推荐

