Articoli di programmazione

Design patterns in pillole: Command

Il Design Pattern Command permette di disaccoppiare il codice che esegue una determinata azione, da quello che serve alla sua esecuzione

command.gif
Iniziamo a definire gli attori:
- Command definisce un'interfaccia per l'esecuzione di un'operazione (ICommand)
- ConcreteCommand eredita da Command, o semplicemente ne implementa l'interfaccia ICommand, ed è la classe concreta che implementa il metodo Execute usato effettivamente dagli altri oggetti del pattern
- Receiver è l'oggetto destinatario dell'azione eseguita dal ConcreteCommand: è quello che contiene la logica applicativa dell'azione eseguita dal Command tramite il metodo Execute
- Invoker si occupa di invocare il ConcreteCommand
- Client crea un ConcreteCommand e gli associa un Receiver

Vediamo in dettaglio alcune porzioni di meta-codice per capire come vanno implementati i vari oggetti.

La classe Receiver contiene le definizioni dei vari metodi che saranno eseguiti dal Command:

public class Receiver
{
public void Insert(){}
public void Delete(){}
}


In concreto possono esistere diversi Receiver ed ognuno può esporre uno o più metodi ai vari Command. Questo dipende dalla nostra architettura.

L'interfaccia ICommand espone il metodo Execute().

public interface ICommand { void Execute(); }


ConcreteCommand implementa il metodo Execute() in base alla propria funzione:
- se si tratta di un InsertCommand, chiamerà il metodo Insert del Receiver
- se si tratta di un DeleteCommand, chiamerà il metodo Delete del Receiver

public class InsertCommand : ICommand
{
public InsertCommand(Receiver receiver) {}
public void Execute()
{
receiver.Insert();
}
}

public class DeleteCommand : ICommand
{
public InsertCommand(Receiver receiver) {}
public void Execute()
{
receiver.Delete();
}
}


Passiamo a Invoker, che si occupa di invocare i vari Command:

public class Invoker
{
public SetCommand(ICommand command)
public int Invoke()
{
command.Execute();
}
}

Basta un Invoker per tutti i Command, dato che questo opera tramite l'interfaccia ICommand.

Alla fine Client organizza tutto per eseguire le varie operazioni.
Facciamo un esempio base senza Dependency Injection:

public void ClientExecution()
{
var insertCommand = new InsertCommand(new Receiver());
var deleteCommand = new DeleteCommand(new Receiver());
var invoker = new Invoker();
invoker.SetCommand(insertCommand);
invoker.Invoke();
invoker.SetCommand(deleteCommand);
invoker.Invoke();
}


#designPatterns #programmazione