2013-12-14 9 views
7

Ich bin Programm in C#, die Sie steuern, indem Sie Befehl so jetzt diktieren, ich habe eine lange switch-Anweisung. So etwas wieRefactor lange Switch-Anweisung

switch (command) 

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

und so weiter

Fast alle Fälle nennen nur ein Verfahren, Methoden sind nicht in einer Klasse, die sie in vielen Klassen verteilt werden. Die Frage ist also, wie ich diesen Schalter auf eine elegantere Weise umgestalten könnte?

+0

sind alle Funktionen mit der gleichen Signatur? – elyashiv

+0

Dies könnte besser für http://codereview.stackexchange.com/ geeignet sein. –

+1

Wann immer Sie Code schreiben, der eine * string * verwendet, um eine Methode darzustellen, sollten Sie zuerst "Delegate" denken. –

Antwort

1

Wenn alle Funktionen die gleichen Parameter erhalten und den gleichen Wert zurückgeben, können Sie mit Dictionary zusammen mit delegates eine Zeichenfolge einer Funktion (en) zuordnen. Mit dieser Methode können Sie auch den Switch in der Laufzeit ändern, so dass externe Programme die Funktionalität des Programms erweitern können.

Wenn die Funktionen nicht identisch sind, könnten Sie Wrapper schreiben - eine Proxy-Funktion, die Parameter wie alle anderen Funktionen erhält und die gewünschten Funktionen aufruft.

+1

Und dann _ "Wie Refactor ich meine Wörterbuch-Füllcode" _ –

0

Das können Sie hier tun. Sie können eine Schnittstelle [ICommand] erstellen, in die Sie eine gemeinsame Funktion einfügen können [zB: Execute].

Dann müssen Sie nur dieses Mitglied mit dem entsprechenden Typ initiieren und die Execute-Funktion aufrufen. Dies könnte zukünftig mehr Funktionen beinhalten und wird somit erweitert.

Sie können auch eine Factory-Methode erstellen, in der Sie den Parameter übergeben und die entsprechende Klasse für die Arbeit verwenden können.

Hoffe, dass hilft.

0

Ich weiß, das ist ein alter Beitrag, aber in diesen Situationen finde ich Attribute und eine Fabrik sehr praktisch.

Der folgende Code verwendet ein benutzerdefiniertes Attribut (Command), mit dem Sie Ihre Methoden zuordnen können, indem Sie einen String-Wert angeben, wie sie auf Sie reagieren sollen.

Die Factory-Methode verwendet Reflektion, um ein Wörterbuch dieser Methoden zu generieren, und ruft es auf, wenn Sie CommandFactory aufrufen.

Die Dinge könnten etwas aufgeräumt werden, Aufruf von Aufruf ist ein wenig hässlich, aber es hängt nur davon ab, wie Sie den Code ausführen möchten.

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<string, MethodInfo> speechMethods = new Dictionary<string, MethodInfo>(); 
     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<CommandAttribute>().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; 
     } 
    } 
} 
7

Sie können dies tun, um Ihre switch-Anweisung Refactoring:

var commands = new Dictionary<string, Action>() 
{ 
    { "Show commands",() => ProgramCommans.ShowAllCommands() }, 
    { "Close window",() => ControlCommands.CloseWindow() }, 
    { "Switch window",() => ControlCommands.SwitchWindow() }, 
}; 

if (commands.ContainsKey(command)) 
{ 
    commands[command].Invoke(); 
} 

Der Hauptvorteil dieses Ansatzes besteht darin, dass Sie den „Schalter“ zur Laufzeit kann sich ändern.

+0

Dies ist ein großer und einfacher Ansatz. Ich mag es besser als meins. +1 – paqogomez

0

Ich weiß, die Antwort ist ein bisschen spät, um das SOLID-Prinzip nicht zu missbrauchen, können Sie Schnittstelle oder Vererbung verwenden. In diesem Beispiel verwende ich die Vererbung, weil Sie möglicherweise andere Verwendungen der Zeichenfolge "command" haben.

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(); 
    } 
}