You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于条件的依赖注入:策略模式下动态注入依赖的实现方案

如何在策略模式中根据运行时条件注入不同依赖?

我目前在使用策略设计模式,想要根据某些运行时条件注入不同的依赖实现。现有代码如下:

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:自定义策略工厂类(通用解耦方案)

把策略的选择逻辑抽离到专门的工厂类中,既保留依赖注入的优势,又能灵活根据条件切换实例:

  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
    }
}
  1. 编写工厂类,注入所有策略实例并提供获取方法:
@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);
        };
    }
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:57:33