基于条件的依赖注入:策略模式下动态注入依赖的实现方案
如何在策略模式中根据运行时条件注入不同依赖?
我目前在使用策略设计模式,想要根据某些运行时条件注入不同的依赖实现。现有代码如下:
public interface Strategy { public void task(); } public class ConcreteStrategyOne implements Strategy { public void task() { // task strategy one } } public class ConcreteStrategyTwo implements Strategy { public void task() { // task strategy two } } public class TaskInHand { private Strategy strategyImpl; @Inject public TaskInHand(Strategy strategyImpl){ this.strategyImpl = strategyImpl; } public void use(Object obj) { if(obj.get("something") == 1){ strategyImpl.task(); // 希望调用ConcreteStrategyOne的task() } else if(obj.get("something") == 2){ strategyImpl.task(); // 希望调用ConcreteStrategyTwo的task() } } }
我知道可以用@Named注解在构造方法里绑定特定类,但我希望能根据上面的条件动态选择注入的依赖——具体来说,当object.get("something")返回1时调用ConcreteStrategyOne的task(),返回2时调用ConcreteStrategyTwo的,该怎么实现呢?
解决方案:用工厂模式结合依赖注入实现动态策略选择
你现在的核心问题是运行时动态切换策略实现,而依赖注入通常是初始化阶段完成的单一实例注入,所以直接在TaskInHand里注入单个Strategy肯定满足不了需求。这里给你两种常用的、低耦合的实现方式:
方式1:自定义策略工厂类(通用解耦方案)
把策略的选择逻辑抽离到专门的工厂类中,既保留依赖注入的优势,又能灵活根据条件切换实例:
- 给每个策略实现添加
@Named注解,让容器能区分不同实例:
@Named("strategyOne") public class ConcreteStrategyOne implements Strategy { public void task() { // task strategy one } } @Named("strategyTwo") public class ConcreteStrategyTwo implements Strategy { public void task() { // task strategy two } }
- 编写工厂类,注入所有策略实例并提供获取方法:
@Singleton public class StrategyFactory { private final Map<String, Strategy> strategyMap; // 依赖注入容器会自动把所有Strategy实现注入到这个Map中 // key是@Named指定的名称,value是对应策略实例 @Inject public StrategyFactory(Map<String, Strategy> strategyMap) { this.strategyMap = strategyMap; } public Strategy getStrategy(int condition) { return switch(condition) { case 1 -> strategyMap.get("strategyOne"); case 2 -> strategyMap.get("strategyTwo"); default -> throw new IllegalArgumentException("Unknown condition: " + condition); }; } }
- 修改
TaskInHand,注入工厂而非单一策略:
public class TaskInHand { private final StrategyFactory strategyFactory; @Inject public TaskInHand(StrategyFactory strategyFactory){ this.strategyFactory = strategyFactory; } public void use(Object obj) { int condition = (int) obj.get("something"); Strategy strategy = strategyFactory.getStrategy(condition); strategy.task(); } }
方式2:利用框架的动态依赖查找(适合Spring/CDI场景)
如果你用的是Spring或者Jakarta CDI这类框架,可以直接在运行时获取对应实例,但这种方式会增加代码与框架的耦合度:
以Spring为例:
public class TaskInHand { private final ApplicationContext context; @Autowired public TaskInHand(ApplicationContext context){ this.context = context; } public void use(Object obj) { int condition = (int) obj.get("something"); Strategy strategy; if(condition == 1) { strategy = context.getBean("strategyOne", Strategy.class); } else if(condition == 2) { strategy = context.getBean("strategyTwo", Strategy.class); } else { throw new IllegalArgumentException("Unknown condition"); } strategy.task(); } }
关键思路总结
- 不要试图在初始化阶段注入“可变”的依赖,依赖注入的核心是初始化时绑定实例,而你的条件是运行时才确定的。
- 把策略选择逻辑抽离到工厂类,让
TaskInHand只专注于业务逻辑,符合单一职责原则。 - 用
@Named(或Spring的@Qualifier)标记不同策略,方便容器识别和批量注入。
内容的提问来源于stack exchange,提问作者learning_to_write_good_code
相关产品推荐
相关产品推荐

