2013-12-14 13 views
7

Sono programma in C# che si sta controllando dettando il comando così ora ho una lunga istruzione switch. Qualcosa di simileDichiarazione interruttore lungo refact

switch (command) 

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

e così via

Quasi tutti i casi chiamare un solo metodo, i metodi non sono in una classe in cui sono distribuiti in molte classi. Quindi la domanda è: come posso refactoring questo passaggio in modo più elegante?

+0

sono tutte le funzioni con la stessa firma? – elyashiv

+0

Questo potrebbe essere più adatto a http://codereview.stackexchange.com/. –

+1

Ogni volta che ti ritrovi a scrivere un codice che usa una * stringa * per rappresentare un metodo, devi prima pensare a "delegare". –

risposta

1

Se tutte le funzioni ottengono gli stessi parametri e restituiscono lo stesso valore, è possibile utilizzare uno Dictionary insieme a delegates per associare una stringa a una o più funzioni. Questo metodo ti consentirà anche di modificare il tempo di esecuzione dello switch, consentendo ai programmi esterni di estendere la funzionalità del programma.

Se le funzioni non sono le stesse, è possibile scrivere wrapper, una funzione proxy che otterrà i parametri come tutte le altre funzioni e chiamerà le funzioni desiderate.

+1

E quindi _ "Come refactoring il mio codice di riempimento del dizionario" _ –

0

Ecco cosa puoi fare qui. È possibile creare un'interfaccia [ICommand] in cui è possibile inserire una funzione comune [es. Esegui].

Quindi è sufficiente avviare quel membro con il tipo appropriato e chiamare la funzione Esegui. Questo potrebbe includere più funzioni in futuro ed è quindi esteso.

Inoltre, è possibile creare un metodo di fabbrica in cui è possibile passare il parametro e ottenere la classe appropriata con cui lavorare.

Spero che questo aiuti.

0

Mi rendo conto che questo è un vecchio post, ma in queste situazioni trovo gli attributi e una fabbrica molto utili.

Il seguente codice utilizza un attributo personalizzato (Command) per consentire di attribuire i metodi, fornendo un valore stringa di come dovrebbero rispondere all'utente.

Il metodo di fabbrica utilizza la riflessione per generare un dizionario di questi metodi e lo chiama ogni volta che si chiama CommandFactory.

Le cose potrebbero essere ripulite un po ', chiamare invoke è un po' brutto, ma dipende solo da come si desidera eseguire il codice.

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

È possibile farlo al refactoring del istruzione switch:

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

Il vantaggio principale di questo approccio è che si può cambiare il "switch" in fase di esecuzione.

+0

Questo è un approccio semplice e di qualità. Mi piace meglio del mio. +1 – paqogomez

0

So che la risposta è un po 'in ritardo, per non abusare del principio SOLID, è possibile utilizzare l'interfaccia o l'ereditarietà. In questo esempio, utilizzo l'ereditarietà perché potresti avere altri usi della stringa "comando".

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