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

依赖注入环境下策略模式的运行时策略选择方案探讨

依赖注入环境下策略模式的运行时选择优化方案

针对你提到的DI容器中按TaskType枚举选择对应ICalculator的场景,除了你列出的两种方案,还有两种更符合SOLID原则且常见的规范实现方式:

1. 直接注入所有策略实现并筛选(推荐用于单例/范围生命周期的策略)

这种方式不需要修改原有ICalculator接口,也无需额外工厂类,利用DI容器支持注入所有服务实现集合的特性:

  • 第一步:给每个ICalculator实现类添加TaskType标识,可以用特性或者只读属性:
    // 用特性标记对应任务类型
    [AttributeUsage(AttributeTargets.Class)]
    public class CalculatorTypeAttribute : Attribute
    {
        public TaskType Type { get; }
        public CalculatorTypeAttribute(TaskType type) => Type = type;
    }
    
    [CalculatorType(TaskType.Sum)]
    public class SumCalculator : ICalculator
    {
        public int Calculate(int a, int b) => a + b;
    }
    
    [CalculatorType(TaskType.Subtraction)]
    public class SubtractionCalculator : ICalculator
    {
        public int Calculate(int a, int b) => a - b;
    }
    
  • 第二步:在客户端注入IEnumerable<ICalculator>,运行时通过筛选找到对应实例:
    public class CalculatorClient
    {
        private readonly IEnumerable<ICalculator> _calculators;
    
        public CalculatorClient(IEnumerable<ICalculator> calculators)
        {
            _calculators = calculators;
        }
    
        public int ExecuteCalculation(TaskType taskType, int a, int b)
        {
            var calculator = _calculators.FirstOrDefault(c => 
                c.GetType().GetCustomAttribute<CalculatorTypeAttribute>()?.Type == taskType);
            
            if (calculator == null)
                throw new InvalidOperationException($"No calculator found for task type: {taskType}");
            
            return calculator.Calculate(a, b);
        }
    }
    

这种方式的优势是遵循单一职责原则:ICalculator只负责计算逻辑,类型匹配逻辑由客户端处理,同时完全利用DI容器管理策略实例的生命周期。

2. 基于DI的轻量工厂模式(推荐用于瞬态生命周期的策略)

如果你的计算器需要每次请求都创建新实例(瞬态),可以优化原有工厂模式,让工厂依赖DI容器而非自行创建实例,避免手动管理对象生命周期:

  • 定义工厂接口:
    public interface ICalculatorFactory
    {
        ICalculator Create(TaskType taskType);
    }
    
  • 工厂实现类注入IServiceProvider,从DI中获取对应实例:
    public class CalculatorFactory : ICalculatorFactory
    {
        private readonly IServiceProvider _serviceProvider;
    
        public CalculatorFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public ICalculator Create(TaskType taskType)
        {
            return taskType switch
            {
                TaskType.Sum => _serviceProvider.GetRequiredService<SumCalculator>(),
                TaskType.Subtraction => _serviceProvider.GetRequiredService<SubtractionCalculator>(),
                _ => throw new InvalidOperationException($"Unsupported task type: {taskType}")
            };
        }
    }
    
  • 客户端注入ICalculatorFactory即可获取对应计算器:
    public class CalculatorClient
    {
        private readonly ICalculatorFactory _factory;
    
        public CalculatorClient(ICalculatorFactory factory)
        {
            _factory = factory;
        }
    
        public int ExecuteCalculation(TaskType taskType, int a, int b)
        {
            var calculator = _factory.Create(taskType);
            return calculator.Calculate(a, b);
        }
    }
    

这种方式既保留了工厂模式的灵活性,又让DI容器全权负责对象的创建和生命周期管理,避免了手动new实例的弊端。

方案对比

  • 你提到的修改ICalculator添加CanHandleTask方法:虽然可行,但会让接口承担了计算之外的类型匹配职责,违反单一职责原则,且所有实现类都要重复实现该方法,冗余度高。
  • 上述两种优化方案:更贴合DI的设计理念,同时遵循SOLID原则,可维护性和扩展性更强——比如新增MultiplicationCalculator时,只需要添加标记特性或在工厂中新增分支(后者还可以通过配置或反射进一步解耦)。

内容的提问来源于stack exchange,提问作者Enrico Massone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 04:01:07