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
相关产品推荐
相关产品推荐

