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

如何在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注册流程:

  1. 注册所有可能的策略到DI容器(生命周期按需选择Scoped/Transient/Singleton)。
  2. 通过工厂或DI键索引,在运行时根据PaymentType动态获取策略。
  3. 新增支付类型时,仅需:
    • 新增实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:30:20