前言
还在为复杂的业务逻辑切换而头疼吗?面对不断变化的需求,是否感觉代码越来越臃肿,维护成本越来越高?
作为一名长期深耕工业软件领域的 C# 开发,深知这种痛苦。一个生产系统今天要支持高速模式,明天又要加入节能策略,后天客户又提出新的质量优先流程——如果用传统的 if-else 或 switch-case 硬编码,不出三个月,核心模块就会变成"意大利面条"。
今天,不讲教科书定义,不堆砌 UML 图,而是通过一个真实可运行的工业控制系统案例,手把手带你用 策略模式 打造一个生产级 WinForm 应用。
你会看到:
-
如何设计清晰的策略接口
-
如何实现具体业务策略(高速/标准/节能)
-
如何与 UI 完美集成
-
那些踩过的坑和避坑指南
最终你将拥有一套可复用、可测试、可扩展的架构模板。
为什么需要策略模式?
传统开发的痛点
想象一个工业产线控制系统,需支持三种典型生产模式:
-
高速生产模式:紧急订单,追求最高产出效率
-
标准生产模式:日常作业,平衡效率与能耗
-
节能生产模式:非高峰时段,优先降低功耗
若采用传统写法,代码很快会变成这样:
// ❌ 糟糕的实现方式
public void StartProduction(string mode, int quantity)
{
if (mode == "HighSpeed")
{
// 高速模式逻辑...
}
else if (mode == "Standard")
{
// 标准模式逻辑...
}
else if (mode == "Eco")
{
// 节能模式逻辑...
}
// 新增模式就要修改这里...
}
问题显而易见:
-
违反开闭原则:每次新增模式都要动核心方法
-
高耦合:业务逻辑与控制流混杂,难以单元测试
-
可读性差:随着策略增多,方法迅速膨胀,新人看不懂、老手不敢改
这不仅是代码问题,更是交付风险。
设计流程
策略模式解决方案
核心设计思想
将可变的算法族封装成独立类,使它们可以互相替换,且不影响使用它们的客户端。
关键在于:解耦"做什么"和"怎么做"。
架构设计
首先定义统一策略接口:
// ✅ 策略接口定义
public interface IProductionStrategy
{
string StrategyName { get; }
ProductionResult Execute(int quantity, double workTime);
string GetDescription();
double GetEfficiency();
double GetPowerConsumption();
}
再定义数据模型,用于承载执行结果:
public class ProductionResult
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public int TargetQuantity { get; set; }
public int ActualQuantity { get; set; }
public double Efficiency { get; set; }
public double PowerConsumption { get; set; }
public string Status { get; set; }
public string StrategyUsed { get; set; }
public double WorkTime { get; set; }
public TimeSpan Duration => EndTime - StartTime;
public double QualityRate => (double)ActualQuantity / TargetQuantity * 100;
}
项目效果
代码实战:具体策略实现
高速生产策略
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AppStrategyIndustrialControlSystem.Interfaces;
using AppStrategyIndustrialControlSystem.Models;
namespace AppStrategyIndustrialControlSystem.Strategies
{
public class HighSpeedStrategy : IProductionStrategy
{
public string StrategyName => "高速生产模式";
public ProductionResult Execute(int quantity, double workTime)
{
var result = new ProductionResult
{
StartTime = DateTime.Now,
TargetQuantity = quantity,
WorkTime = workTime,
StrategyUsed = StrategyName
};
// 高速模式:效率高,但功耗大
double efficiency = GetEfficiency();
double powerConsumption = GetPowerConsumption();
// 模拟生产过程
System.Threading.Thread.Sleep(1000); // 模拟处理时间
result.ActualQuantity = (int)(quantity * efficiency);
result.Efficiency = efficiency;
result.PowerConsumption = powerConsumption * workTime;
result.EndTime = DateTime.Now;
result.Status = result.ActualQuantity >= quantity * 0.95 ? "生产完成" : "需要调整";
return result;
}
public string GetDescription()
{
return "适用于紧急订单,最大化生产速度,功耗较高";
}
public double GetEfficiency()
{
return 0.98; // 98% 效率
}
public double GetPowerConsumption()
{
return 150.0; // 150kW/小时
}
}
}
类似地,StandardStrategy 和 EcoModeStrategy 只需实现相同接口,返回不同的效率、功耗和描述。
上下文管理器
策略不能孤立存在,需要一个"调度中心":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AppStrategyIndustrialControlSystem.Interfaces;
using AppStrategyIndustrialControlSystem.Models;
namespace AppStrategyIndustrialControlSystem.Context
{
public class ProductionContext
{
private IProductionStrategy _strategy;
public ProductionContext(IProductionStrategy strategy)
{
_strategy = strategy;
}
public void SetStrategy(IProductionStrategy strategy)
{
_strategy = strategy;
}
public ProductionResult ExecuteProduction(int quantity, double workTime)
{
return _strategy?.Execute(quantity, workTime);
}
public IProductionStrategy GetCurrentStrategy()
{
return _strategy;
}
}
}
上下文持有当前策略引用,并提供统一调用入口。
UI 设计:工业级界面实现
控件命名规范
遵循工业软件惯例:
-
Button →
btn -
ComboBox →
cmb -
DataGridView →
dgv -
NumericUpDown →
nud
核心界面代码
初始化顺序至关重要:
private void InitializeData()
{
// ⚠️ 重要:正确的初始化顺序
InitializeStrategies(); // 1. 策略列表
InitializeContext(); // 2. 上下文
InitializeDataGridView(); // 3. 数据网格
SetDefaultStrategy(); // 4. 默认选项
}
private void cmbStrategy_SelectedIndexChanged(object sender, EventArgs e)
{
// 🛡️ 防御性编程
if (cmbStrategy.SelectedItem is IProductionStrategy selectedStrategy &&
_productionContext != null)
{
_productionContext.SetStrategy(selectedStrategy);
UpdateStrategyInfo(selectedStrategy);
}
}
常见问题提醒
NullReferenceException 陷阱
问题:在 Form 构造函数中填充 ComboBox 时,会触发 SelectedIndexChanged 事件,但此时 _productionContext 尚未初始化,导致空引用异常。
解决方案:临时移除事件处理器。
// ✅ 临时移除事件处理器
cmbStrategy.SelectedIndexChanged -= cmbStrategy_SelectedIndexChanged;
// 初始化操作...
cmbStrategy.SelectedIndexChanged += cmbStrategy_SelectedIndexChanged;
Readonly 字段赋值问题
若将策略列表声明为 readonly,则无法在 InitializeStrategies() 中赋值:
// ❌ 错误
private readonly List<IProductionStrategy> _strategies;
// ✅ 正确
private List<IProductionStrategy> _strategies;
异步操作最佳实践
避免 UI 冻结,必须异步执行耗时操作:
private async void btnExecute_Click(object sender, EventArgs e)
{
btnExecute.Enabled = false;
pgbProgress.Visible = true;
try
{
// 🚀 异步执行,避免UI冻结
var result = await Task.Run(() =>
_productionContext.ExecuteProduction(quantity, workTime));
// 更新UI...
}
catch (Exception ex)
{
MessageBox.Show($"生产过程发生错误:{ex.Message}", "错误");
}
finally
{
btnExecute.Enabled = true;
pgbProgress.Visible = false;
}
}
实际应用场景
策略模式远不止用于生产模式切换:
-
工业控制系统:设备参数动态调整、报警阈值策略
-
金融交易系统:多套风控规则、止盈止损算法
-
游戏开发:AI 行为树、难度自适应逻辑
-
电商系统:运费计算、折扣策略、会员等级服务
只要存在"同一问题多种解法",策略模式就是首选。
策略模式的核心优势
-
高度灵活:运行时动态切换算法,无需重启或重编译
-
易于扩展:新增策略只需实现接口,零侵入现有代码
-
便于测试:每个策略可独立 Mock 和验证
-
代码整洁:彻底消除 if-else 膨胀,提升可读性与可维护性
进阶建议
工厂模式结合
public static class StrategyFactory
{
public static IProductionStrategy CreateStrategy(string strategyType)
{
return strategyType switch
{
"HighSpeed" => new HighSpeedStrategy(),
"Standard" => new StandardStrategy(),
"Eco" => new EcoModeStrategy(),
_ => throw new ArgumentException("未知策略类型")
};
}
}
配置化管理
将策略参数外置到 appsettings.json:
{
"ProductionStrategies": {
"HighSpeed": {
"Efficiency": 0.98,
"PowerConsumption": 150.0
}
}
}
策略缓存
避免重复创建实例:
private static readonly Dictionary<string, IProductionStrategy> _strategyCache
= new Dictionary<string, IProductionStrategy>();
数据持久化
public interface IDataRepository
{
Task SaveProductionResultAsync(ProductionResult result);
Task<List<ProductionResult>> GetHistoryAsync(DateTime from, DateTime to);
}
实时监控
public event EventHandler<ProductionEventArgs> ProductionStatusChanged;
private void NotifyProductionStatus(ProductionResult result)
{
ProductionStatusChanged?.Invoke(this, new ProductionEventArgs(result));
}
总结
通过这个完整的工业控制系统案例,我们验证了策略模式在真实项目中的强大价值:
1、架构清晰:接口抽象 + 具体实现,职责分明
2、扩展无忧:新增生产模式?只需加一个类,不碰一行旧代码
3、工程可靠:从异常处理到异步调用,覆盖生产环境所有细节
策略模式不是炫技,而是应对变化的工程智慧。它教会我们:好的架构不是预测未来,而是让未来的变化成本最低。
当你下次面对一堆 if-else 时,不妨问自己一句:"这些分支,是不是该交给策略来管了?"
关键词
C#、策略模式、设计模式、WinForm、工业控制、IProductionStrategy、ProductionContext、策略接口、开闭原则、代码重构、异步执行、防御性编程、工厂模式、配置化管理
mp.weixin.qq.com/s/AOfq9oq5Oo_1uraAzWDmrA
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!