重构长切换语句

我在c#中编程,你通过口述命令控制,所以现在我有一个很长的switch语句。 就像是

switch (command) { case "Show commands": ProgramCommans.ShowAllCommands(); break; case "Close window": ControlCommands.CloseWindow(); break; case "Switch window": ControlCommands.SwitchWindow(); break; } 

等等

几乎所有情况都只调用一个方法,方法不在一个类中,它们分布在许多类中。 所以问题是,我如何能够将这种转换重构为更优雅的方式?

您可以这样做来重构您的switch语句:

 var commands = new Dictionary() { { "Show commands", () => ProgramCommans.ShowAllCommands() }, { "Close window", () => ControlCommands.CloseWindow() }, { "Switch window", () => ControlCommands.SwitchWindow() }, }; if (commands.ContainsKey(command)) { commands[command].Invoke(); } 

这种方法的主要优点是您可以在运行时更改“切换”。

如果所有函数都获得相同的参数并返回相同的值,则可以使用Dictionary和委托将字符串映射到函数。 此方法还允许您更改交换机的运行时间 – 允许外部程序扩展程序的function。

如果函数不相同,你可以编写包装器 – 一个代理函数,它将获取所有其他函数的参数,并调用你想要的函数。

这是你在这里可以做的。 您可以创建一个接口[ICommand],您可以在其中放置一个公共function[例如:执行]。

然后,您只需要使用适当的类型启动该成员并调用Execute函数。 这可能包括将来的更多function,因此得到了扩展。

此外,您可以创建一个工厂方法,您可以在其中传递参数并获取要使用的相应类。

希望有所帮助。

我意识到这是一个老post,但在这些情况下,我发现属性和工厂非常方便。

以下代码使用自定义属性( Command )来允许您对方法进行属性化,并提供它们应如何响应您的字符串值。

工厂方法使用reflection生成这些方法的字典,并在调用CommandFactory时调用它。

事情可能会被清理一下,调用invoke有点难看,但这取决于你想如何执行代码。

 using System.Collections.Generic; using System.Linq; namespace MyApp { using System.Reflection; using MyApp.Commands; class Program { static void Main(string[] args) { var methods = new MyCommands(); MethodInfo myMethod; myMethod = CommandFactory.GetCommandMethod("Show Commands"); myMethod.Invoke(methods, null); myMethod = CommandFactory.GetCommandMethod("Close window"); myMethod.Invoke(methods, null); myMethod = CommandFactory.GetCommandMethod("Switch window"); myMethod.Invoke(methods, null); } } public static class CommandFactory { private static Dictionary speechMethods = new Dictionary(); public static MethodInfo GetCommandMethod(string commandText) { MethodInfo methodInfo; var commands = new MyCommands(); if (speechMethods.Count == 0) { var methodNames = typeof(MyCommands).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); var speechAttributeMethods = methodNames.Where(y => y.GetCustomAttributes().OfType().Any()); foreach (var speechAttributeMethod in speechAttributeMethods) { foreach (var attribute in speechAttributeMethod.GetCustomAttributes(true)) { speechMethods.Add(((CommandAttribute)attribute).Command, speechAttributeMethod); } } methodInfo = speechMethods[commandText]; } else { methodInfo = speechMethods[commandText]; } return methodInfo; } } } namespace MyApp.Commands { class MyCommands { [Command("Show All")] [Command("Show All Commands")] [Command("Show commands")] public void ShowAll() { ProgramCommands.ShowAllCommands(); } [Command("Close Window")] public void CloseWindow() { ControlCommands.CloseWindow(); } [Command("Switch Window")] public void SwitchWindow() { ControlCommands.SwitchWindow(); } } [System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple = true)] public class CommandAttribute : System.Attribute { public string Command { get; set; } public CommandAttribute(string textValue) { this.Command = textValue; } } } 

我知道答案有点晚,为了不滥用SOLID原则,你可以使用接口或inheritance。 在这个例子中,我使用inheritance,因为你可能有其他用法的“命令”字符串。

 public abstract class commandRepository { string command ; // if there is no usage in other function class, you can get rid of it public abstract void DoCommands(); } public class ShowCommands:commandRepository { public ShowCommands (){ command ="Show commands"; // if there is no usage in other function class, you can get rid of it } public override void DoCommands(){ ProgramCommans.ShowAllCommands(); } } public class CloseWindow:commandRepository { public CloseWindow (){ command ="Close window"; // if there is no usage in other function class, you can get rid of it } public override void DoCommands(){ ProgramCommans.CloseWindow(); } } public class SwitchWindow:commandRepository { public SwitchWindow (){ command ="Switch window"; // if there is no usage in other function class, you can get rid of it } public override void DoCommands(){ ProgramCommans.SwitchWindow(); } }