Monday, October 5, 2009

Long Method: Replace Conditional Dispatcher with Command

Continuiamo con lo smell: Long Method
  

Problema:

Logiche condizionali vengono usate per le richieste di dispaccio e per eseguire azioni.
Un esempio di logica errata:
if (ac.Name.Equals("ATTACCO"))
// ...
else if (ac.Name.Equals("DIFESA"))
// ...
else if (ac.Name.Equals("BERSERK"))
// ...
else if (ac.Name.Equals("GUARDINGO"))
// ...

Motivazione:
Molti sistemi ricevono, instradano e lavorano con richieste.
Un conditional-dispatcher è un grosso blocco condizionale (if-else o switch) che si occupa di fare il gestire i messaggi ricevuti.

Le due maggiori motivazioni al refactoring di un conditional-dispatcher con una soluzione basata sul pattern Command sono:



  1. Poca flessibilità a runtime
  2. Uno conditional-dispatcher enorme
Il pattern Command rappresenta un’ottima soluzione per rispondere alla motivazioni precedenti.
Il pattern crea una differenza tra il client e gli oggetti che eseguono le operazioni. Questo pattern è estremamente versatile, supporta:



  • Spedire le request a differenti destinatari
  • Queue, logging e richieste da fiutare
  • Transazioni ad alto livello da operazioni primitive
  • Funzionalità di Redo e Undo
Tenendo conto della regola tenere tutto semplice si potrebbe storcere il naso sull’applicazione di questo pattern come soluzione al nostro problema.
Qual’ora il conditional-dispatcher dovrebbe diventare corposo bisogna ricordare che il pattern Command è facile da implementare, versatile e incredibilmente utile.

Soluzione:
Ecco come si mostrerà il codice di sopra applicando il State:

class CommandPattern
{
delegate void Invoker();
static Invoker Execute, Undo, Redo;

class Command
{
public Command(Receiver receiver)
{
Execute = receiver.Action;
Redo = receiver.Action;
Undo = receiver.Reverse;
}
}

public class Receiver
{
string build, oldbuild;
string s = "some string ";
public void Action()
{
oldbuild = build;
build += s;
Console.WriteLine("Receiver is adding " + build);
}

public void Reverse()
{
build = oldbuild;
Console.WriteLine("Receiver is reverting to " + build);
}
}

static void Main()
{
new Command(new Receiver());
Execute();
Redo();
Undo();
Execute();
Console.ReadLine();
}
}

 




Benefici e non
+ Crea un semplice meccaniscmo per l’esecuzione di diversi comportament in una maniera uniforme.
+ Da la possibilità di cambiare a runtime quali richieste sono gestite e come.
+ Richiede un’implementazione semplice.

- Complica il design se le condizioni sono poche.
E non prendete come scusa: “il mio sistema ormai è troppo evoluto per poterne apportare queste migliorie. E’ troppo tardi.”
Se fosse realmente così non esisterebbe il Refactoring :)
Per questo post ho preso spunto da libro Refactoring To Patterns di Joshua Kerievsky.

No comments:

Post a Comment