2013-03-24 12 views
6

Attualmente sto studiando modelli di progettazione e attualmente sto osservando lo schema di comando.In C# come implementare correttamente il modello di progettazione del comando?

Ecco il mio codice corrente:

// this is the receiver 
class Calculator : IReceiver 
{ 
    int x; 
    int y; 

    CommandOptions command; 

    public Calculator(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public void SetAction(CommandOptions command) 
    { 
     this.command = command; 
    } 

    public int GetResult() 
    { 
     int result = 0; 

     switch(this.command) 
     { 
      case CommandOptions.ADD: 
       result = this.x + this.y; 
       break; 

      case CommandOptions.SUBTRACT: 
       result = this.x - this.y; 
       break; 

      case CommandOptions.MULTIPLY: 
       result = this.x * this.y; 
       break; 
     } 

     return result; 
    } 
} 

// command 
abstract class Command 
{ 
    protected IReceiver receiver; 

    public Command(IReceiver receiver) 
    { 
     this.receiver = receiver; 
    } 

    public abstract int Execute(); 
} 

class AddCommand : Command 
{ 
    public AddCommand(IReceiver receiver) : base(receiver) 
    { 
    } 

    public override int Execute() 
    { 
     reciever.SetAction(CommandOptions.ADD); 
     return receiver.GetResult(); 
    } 
} 

enum CommandOptions 
{ 
    ADD, 
    SUBTRACT, 
    MULTIPLY 
} 

interface IReceiver 
{ 
    void SetAction(CommandOptions command); 
    int GetResult(); 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     IReceiver receiver = new Calculator(500, 25); 

     //#Issue:The SetAction() method of the receiver is accessible. 
     //receiver.SetAction(CommandOptions.ADD); 
     receiver.SetAction(CommandOptions.MULTIPLY); 
     Command command = null; 

     Console.Write("Enter option 1-3: "); 

     int commandOption = int.Parse(Console.ReadLine()); 

     switch(commandOption) 
     { 
      case 1: 
       command = new AddCommand(receiver); 
       break; 

      case 2: 
       command = new SubtractCommand(receiver); 
       break; 

      case 3: 
       command = new MultiplyCommand(receiver); 
       break; 

      default: 
       command = new AddCommand(receiver); 
       break; 
     } 

     Console.WriteLine(command.Execute()); 
     Console.ReadKey(); 
    } 
} 

Si noti che nel mio metodo principale, posso accedere al metodo del ricevitore, che è in grado di impostare il comando che desiderate utilizzare SetAction.

La mia domanda è: la mia implementazione viola lo scopo del modello di comando e la mia implementazione è errata perché sono in grado di accedervi nel mio codice cliente? In tal caso, come posso migliorare questa implementazione.

+0

Perché il rigamarole con enum CommandOptions e il complicato metodo Calculator.GetResult()? –

+1

Potresti trovare utile questo collegamento, sia per il pattern Command che per gli altri pattern di progettazione su cui hai lavorato: http://www.dofactory.com/Patterns/PatternCommand.aspx. –

+1

Ti incoraggio a leggere questi articoli ... [.NET Junkie Command Architecture] (http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91) e [.NET Junkie Query Architettura] (http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92) – TylerOhlsen

risposta

7

Ho eseguito un tentativo di modifica del testo (non l'ho eseguito, si aspettano errori di sintassi :)) il codice. Ecco come modellerei il tuo problema.

Alcuni punti-

1) Avere il comando fare l'azione. Nel tuo caso, hai classi di comando, ma la calcolatrice mantiene la logica per il calcolo. Piuttosto, incapsula l'azione di comando all'interno della classe di comando stessa

2) Ho messo una fabbrica per mappare l'opzione di comando al comando e salvato alcune righe rimuovendo lo break s dal momento che posso restituire il comando.

3) L'IReceiver ora contiene i valori passati al comando. In questo caso, poiché i nostri operatori sono tutti binari, ho appena usato X e Y. Può essere un array o qualsiasi altro tipo complesso per altri casi.

4) L'enum non è richiesto, a meno che non lo si voglia assolutamente.

Modifica On ri-guarda, credo che una soluzione ancora migliore sarebbe quella di non registrare il ricevitore con i comandi, invece trasmettere i parametri, mentre invoca il comando.

//this is the receiver 
class Calculator : IReceiver 
{ 
    int y; 
    int x; 

    public Calculator(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public int Calculate(int commandOption) 
    { 
     Command command = new CommandFactory().GetCommand(commandOption); 
     return command.Execute(x , y); 
    } 

} 


//command 
interface ICommand 
{  
    int Execute(int x, int y); 
} 

class AddCommand : Command 
{ 
    public override int Execute(int x, int y) 
    { 
     return x + y; 
    } 
} 

class MultiplyCommand : Command 
{ 
    public override int Execute(int x, int y) 
    { 
     return x * y; 
    } 
} 

class SubtractCommand : Command 
{ 
    public override int Execute(int x, int y) 
    { 
     return x - y; 
    } 
} 

interface IReceiver 
{ 
    int X {get; set;} 
    int Y {get; set;} 
    int Calculate(int commandOption); 
} 

public class CommandFactory 
{ 
    public GetCommand(int commandOption) 
    { 
     switch(commandOption) 
     { 
      case 1: 
       return new AddCommand(); 
      case 2: 
       return new SubtractCommand(); 
      case 3: 
       return new MultiplyCommand(); 
      default: 
       return new AddCommand(); 
     }  
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IReceiver receiver = new Calculator(500, 25); 
     //#Issue:The SetAction() method of the receiver is accessible. 
     //receiver.SetAction(CommandOptions.ADD); 

     //Receiver no longer exposes SetAction 
     //receiver.SetAction(CommandOptions.MULTIPLY); 
     Console.Write("Enter option 1-3: "); 
     int commandOption = int.Parse(Console.ReadLine()); 

     Console.WriteLine(receiver.Calculate(commandOption)); 
     Console.ReadKey(); 
    } 
}