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

C#策略模式正确用法:重构代码时的IOC参数传递疑问

重构到策略模式的正确姿势(解决IOC下的策略实例化问题)

首先,你现在的问题核心是不要手动实例化策略类——因为手动new StrategyA(_a, _b)会把策略类的依赖绑定到ExampleService里,不仅破坏了依赖注入的解耦优势,还让ExampleService需要知道所有策略的构造参数,这完全违背了策略模式的初衷。

下面给你两种最常用的、符合IOC规范的重构方案:

方案一:使用策略工厂(推荐,解耦更彻底)

我们可以创建一个专门的工厂类,负责根据需求提供对应的IReminderStrategy实例,所有策略的依赖都由IOC容器注入到工厂里,ExampleService只需要和工厂交互即可。

步骤1:定义提醒类型枚举(用来区分不同策略)

public enum ReminderType
{
    Invite,
    Booking
}

步骤2:修改策略接口(可选,用来标识策略对应的类型)

让策略自身声明对应的类型,方便工厂识别:

public interface IReminderStrategy 
{
    ReminderType ReminderType { get; }
    Task GenerateReminders(string executedBy);
}

// StrategyA实现
public class StrategyA : IReminderStrategy 
{
    public ReminderType ReminderType => ReminderType.Invite;
    private readonly IInterfaceA _a;
    private readonly IInterfaceB _b;

    public StrategyA(IInterfaceA a, IInterfaceB b) 
    {
        _a = a;
        _b = b;
    }

    public async Task GenerateReminders(string executedBy)
    {
        // 原GenerateInviteReminders的业务逻辑
    }
}

// StrategyB实现
public class StrategyB : IReminderStrategy 
{
    public ReminderType ReminderType => ReminderType.Booking;
    private readonly IInterfaceA _a;
    private readonly IInterfaceB _b;

    public StrategyB(IInterfaceA a, IInterfaceB b) 
    {
        _a = a;
        _b = b;
    }

    public async Task GenerateReminders(string executedBy)
    {
        // 原GenerateBookingReminders的业务逻辑
    }
}

步骤3:创建策略工厂

public class ReminderStrategyFactory
{
    private readonly IEnumerable<IReminderStrategy> _strategies;

    // 注入所有已注册的IReminderStrategy实现类
    public ReminderStrategyFactory(IEnumerable<IReminderStrategy> strategies)
    {
        _strategies = strategies;
    }

    public IReminderStrategy GetStrategy(ReminderType type)
    {
        var strategy = _strategies.FirstOrDefault(s => s.ReminderType == type);
        if (strategy == null)
        {
            throw new ArgumentException($"No strategy found for reminder type: {type}");
        }
        return strategy;
    }
}

步骤4:修改ExampleService使用工厂

public class ExampleService 
{
    private readonly ReminderStrategyFactory _strategyFactory;

    // 注入工厂,而非直接注入策略的依赖
    public ExampleService(ReminderStrategyFactory strategyFactory) 
    {
        _strategyFactory = strategyFactory;
    }

    // 统一的调用入口
    public async Task GenerateReminders(ReminderType type, string executedBy)
    {
        var strategy = _strategyFactory.GetStrategy(type);
        await strategy.GenerateReminders(executedBy);
    }

    // 兼容原IReminderService接口的方法(可选,平滑过渡)
    public async Task GenerateInviteReminders(string executedBy)
    {
        await GenerateReminders(ReminderType.Invite, executedBy);
    }

    public async Task GenerateBookingReminders(string executedBy)
    {
        await GenerateReminders(ReminderType.Booking, executedBy);
    }
}

方案二:直接注入策略字典(更简洁,适合简单场景)

如果你的策略类型不多,也可以直接在ExampleService里注入一个Dictionary<ReminderType, IReminderStrategy>,由IOC容器自动填充这个字典(主流容器如Microsoft DI、Autofac都支持这种集合注入)。

修改ExampleService:

public class ExampleService 
{
    private readonly Dictionary<ReminderType, IReminderStrategy> _strategyMap;

    public ExampleService(Dictionary<ReminderType, IReminderStrategy> strategyMap) 
    {
        _strategyMap = strategyMap;
    }

    public async Task GenerateReminders(ReminderType type, string executedBy)
    {
        if (!_strategyMap.TryGetValue(type, out var strategy))
        {
            throw new ArgumentException($"No strategy found for reminder type: {type}");
        }
        await strategy.GenerateReminders(executedBy);
    }
}

容器配置(以Microsoft DI为例):

// 注册所有策略实现
services.AddScoped<IReminderStrategy, StrategyA>();
services.AddScoped<IReminderStrategy, StrategyB>();

// 注册字典:从已注册的策略中构建映射关系
services.AddScoped<Dictionary<ReminderType, IReminderStrategy>>(sp =>
{
    var strategies = sp.GetRequiredService<IEnumerable<IReminderStrategy>>();
    return strategies.ToDictionary(s => s.ReminderType);
});

关键注意点

  • 永远不要在业务类里手动new策略类,把实例化的工作交给IOC容器或者工厂,这样才能保持代码的解耦和可维护性。
  • 原来的IReminderService接口可以保留,让ExampleService实现它,这样不需要修改调用方的代码,平滑过渡到策略模式。

内容的提问来源于stack exchange,提问作者Mukil Deepthi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:34:08