重构:用Command替换条件调度程序
注:该随笔受启发于 《重构与模式》 第七章 第7.6小节 用Command替换条件调度程序 。
对于Command不做过多解释,这里我找了两个例子、供部分园友参阅:Command例子1 Command例子2 。
条件调度程序:我对这个名词的理解为,它是相对简单的选择结构 与 相对独立的业务逻辑的结合体。
话不是很好理解,下面举个小例子吧。
重构前的代码:
/// <summary> /// 很简单的选择分支 一层 if else /// N个 相对独立 任务 /// </summary> /// <param name="actionName"></param> public void DoAction(string actionName) { if (actionName == "Action1") { // 处理 Action1任务 Console.WriteLine("执行任务1"); } else if (actionName == "Action2") { // 处理 Action2任务 Console.WriteLine("执行任务2"); } else if (actionName == "Action3") { // 处理 Action3任务 // 无处理操作 } }
在 《重构与模式》 一文中的重构的做法是:
为每一个动作创建一个Command,把这些Command存储在一个集合中, 并用获取及执行Command的代码替换条件逻辑。
重构步骤我不做详细描述,看一下重构后的结果吧:
public class class2 { private Dictionary<string, CommandAbstract> dic; public class2() { this.dic = new Dictionary<string, CommandAbstract>(); this.dic.Add("Action1", new Command1()); this.dic.Add("Action2", new Command2()); this.dic.Add("Action3", new Command3()); } /// <summary> /// 应用 Command模式 替换 条件调度程序/// </summary> /// <param name="actionName"></param> public void DoAction(string actionName) { CommandAbstract command = null; if (dic.ContainsKey(actionName)) { command = dic[actionName]; } if (command != null) { command.Execute(); } } } public abstract class CommandAbstract { public abstract void Execute(); } public class Command1 : CommandAbstract { public override void Execute() { Console.WriteLine("执行任务1"); } } public class Command2 : CommandAbstract { public override void Execute() { Console.WriteLine("执行任务2"); } } public class Command3 : CommandAbstract { public override void Execute() { } }
看着 硬编码 Dictionary 很不爽,如果经常需要添加新Command, 有可能还需要继续重构——使其遵循开闭原则。
方案:使用反射代替硬编码 (简单的Plugin模式),重构后的结果如下:
public static class CommandFactory { private static Dictionary<string, CommandAbstract> dic; static CommandFactory() { dic = new Dictionary<string, CommandAbstract>(); Type absType = typeof(CommandAbstract); Assembly assem = absType.Assembly; foreach (Type t in assem.GetTypes()) { if (t.IsClass && !t.IsAbstract && t.IsSubclassOf(absType)) { CommandAbstract command = Activator.CreateInstance(t) as CommandAbstract; if (command != null && !dic.ContainsKey(command.CommandName)) { dic.Add(command.CommandName, command); } } } } public static CommandAbstract GetCommand(string commandName) { if (dic.ContainsKey(commandName)) { return dic[commandName]; } return null; } } public class class2 {/// <summary> /// 重构硬编码/// </summary> /// <param name="actionName"></param> public void DoAction(string actionName) { CommandAbstract command = CommandFactory.GetCommand(actionName); if (command != null) { command.Execute(); } } } public abstract class CommandAbstract { public string CommandName { get; protected set; } public abstract void Execute(); } public class Command1 : CommandAbstract { public Command1() { this.CommandName = "Action1"; } public override void Execute() { Console.WriteLine("执行任务1"); } } public class Command2 : CommandAbstract { public Command2() { this.CommandName = "Action2"; } public override void Execute() { Console.WriteLine("执行任务2"); } } public class Command3 : CommandAbstract { public Command3() { this.CommandName = "Action3"; } public override void Execute() { } }
如果 条件表达式 较为复杂呢,那又可以怎样重构?
提示:责任链模式。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?