如何在C#中结合依赖注入实现策略模式的条件选择
策略模式在支付处理中的实践与疑问解答
一、条件逻辑的实现位置与策略注册
你不用纠结“工厂实例化还是DI容器实例化”——两者可以结合,让DI容器负责创建策略实例,工厂只负责选择实例,而非创建。
1. 结合DI容器的工厂模式(推荐方案)
步骤1:注册所有策略到DI容器
以.NET为例,在启动时将所有支付策略注册到DI容器,由容器管理实例生命周期:
// 注册各支付策略 services.AddScoped<IPaymentStrategy, CreditCardPaymentStrategy>(); services.AddScoped<IPaymentStrategy, DebitCardPaymentStrategy>(); services.AddScoped<IPaymentStrategy, PayPalPaymentStrategy>(); // 若策略类遵循统一命名规范,也可通过反射批量注册
步骤2:实现策略工厂
注入所有策略实例集合,通过PaymentType映射选择对应策略:
public class PaymentStrategyFactory { private readonly Dictionary<PaymentType, IPaymentStrategy> _strategyMap; public PaymentStrategyFactory(IEnumerable<IPaymentStrategy> strategies) { _strategyMap = new Dictionary<PaymentType, IPaymentStrategy> { { PaymentType.CREDIT_CARD, strategies.First(s => s is CreditCardPaymentStrategy) }, { PaymentType.DEBIT_CARD, strategies.First(s => s is DebitCardPaymentStrategy) }, { PaymentType.PAYPAL, strategies.First(s => s is PayPalPaymentStrategy) } }; } public IPaymentStrategy GetStrategy(PaymentType paymentType) { if (_strategyMap.TryGetValue(paymentType, out var strategy)) { return strategy; } throw new ArgumentOutOfRangeException(nameof(paymentType), "不支持的支付类型"); } }
步骤3:修改PaymentProcessor支持动态策略
让处理器通过工厂获取对应策略,实现运行时切换:
public class PaymentProcessor { private readonly PaymentStrategyFactory _strategyFactory; public PaymentProcessor(PaymentStrategyFactory strategyFactory) { _strategyFactory = strategyFactory; } public void ProcessPayment(double amount, PaymentType paymentType) { var strategy = _strategyFactory.GetStrategy(paymentType); strategy.ProcessPayment(amount); } }
2. DI容器直接处理策略映射(进阶方案)
部分DI容器(如Autofac)支持按键注册服务,可将PaymentType作为键,直接从容器中索引获取策略:
// Autofac注册示例 builder.RegisterType<CreditCardPaymentStrategy>().Keyed<IPaymentStrategy>(PaymentType.CREDIT_CARD); builder.RegisterType<DebitCardPaymentStrategy>().Keyed<IPaymentStrategy>(PaymentType.DEBIT_CARD); builder.RegisterType<PayPalPaymentStrategy>().Keyed<IPaymentStrategy>(PaymentType.PAYPAL); // 工厂通过索引获取策略 public class PaymentStrategyFactory { private readonly IIndex<PaymentType, IPaymentStrategy> _strategyIndex; public PaymentStrategyFactory(IIndex<PaymentType, IPaymentStrategy> strategyIndex) { _strategyIndex = strategyIndex; } public IPaymentStrategy GetStrategy(PaymentType paymentType) { if (_strategyIndex.TryGetValue(paymentType, out var strategy)) { return strategy; } throw new ArgumentOutOfRangeException(nameof(paymentType)); } }
这种方式完全由DI容器管理策略生命周期,工厂仅做索引查询,更符合DI设计思想。
二、策略模式与依赖注入:互补而非对立
两者并非同一层面的概念,不存在“选哪个”的问题:
- 策略模式是设计模式,核心是封装不同行为并实现可替换,解决
if-else分支冗余问题,让行为扩展更灵活。 - 依赖注入是设计原则/技术,核心是控制反转,解决对象耦合问题,让实例创建与依赖管理更清晰。
你的场景中,两者是完美搭配:用策略模式封装支付行为,用DI容器管理策略实例,用工厂作为桥梁完成策略选择。
三、无需修改DI注册实现运行时切换
要实现动态切换且不修改DI注册,关键是不绑定固定策略到DI注册流程:
- 注册所有可能的策略到DI容器(生命周期按需选择Scoped/Transient/Singleton)。
- 通过工厂或DI键索引,在运行时根据
PaymentType动态获取策略。 - 新增支付类型时,仅需:
- 新增实现
IPaymentStrategy的类。 - 给类添加标识特性(如
[PaymentStrategy(PaymentType.ALIPAY)]),通过反射自动扫描映射,无需手动修改DI注册或工厂代码。
- 新增实现
示例特性实现:
[AttributeUsage(AttributeTargets.Class)] public class PaymentStrategyAttribute : Attribute { public PaymentType PaymentType { get; } public PaymentStrategyAttribute(PaymentType paymentType) => PaymentType = paymentType; } [PaymentStrategy(PaymentType.CREDIT_CARD)] public class CreditCardPaymentStrategy : IPaymentStrategy { ... }
工厂通过反射自动构建映射:
public PaymentStrategyFactory(IServiceProvider serviceProvider) { _strategyMap = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes()) .Where(t => typeof(IPaymentStrategy).IsAssignableFrom(t) && !t.IsInterface) .Select(t => new { Type = t, Attr = t.GetCustomAttribute<PaymentStrategyAttribute>() }) .Where(x => x.Attr != null) .ToDictionary( x => x.Attr.PaymentType, x => (IPaymentStrategy)serviceProvider.GetService(x.Type) ); }
内容的提问来源于stack exchange,提问作者tase akpo
相关产品推荐
相关产品推荐

