Quem já quis implementar acções tais como Undo e Redo de operações nos seus componentes e acabou embrulhado? (ehhrrrr, EU!)
Apresento aqui uma simples aplicação práctica do mesmo, sob a forma de uma calculadora que suporta níveis ilimitados (bem... limitados à memória) de undo/redo.
using System;
using System.Collections;
// "Classe abstracta Command" - Esta tem as operações base que queremos implementar - Execute e UnExecute
abstract class Command
{ // Methods
abstract public void Execute();
abstract public void UnExecute();
}
// Esta classe é o nosso ConcreteCommand - A calculadora. recebemos o objecto calculadora, tipo de operação e operando
class CalculatorCommand : Command
{ // Fields Operador (* + - /) e operando (neste caso inteiro para simplificar o exemplo)
char operador;
int operando;
Calculadora calculadora;
public CalculatorCommand( Calculadora calculadora, char operador, int operando )
{ this.calculadora = calculadora;
this.operador = operador;
this.operando = operando;
}
public char Operador
{ set{ operador = value; } }
public int Operando
{ set{ operando = value; } }
override public void Execute()
{ calculadora.Operation( operador, operando );
}
override public void UnExecute()
{ calculadora.Operation( Undo( operador ), operando );
}
private char Undo( char operador )
{ char undo = ' ';
// Negar a operação - A operação UNDO desfaz, ou executa a operação inversa
switch( operador )
{ case '+': undo = '-'; break;
case '-': undo = '+'; break;
case '*': undo = '/'; break;
case '/': undo = '*'; break;
}
return undo;
}
}
// Receiver - Aqui está o objecto calculadora propriamente dito, com as 4 operações base e o total
class Calculadora
{ private int total = 0;
public void Operation( char operador, int operando )
{ switch( operador )
{ case '+': total += operando; break;
case '-': total -= operando; break;
case '*': total *= operando; break;
case '/': total /= operando; break;
}
Console.WriteLine( "Total = {0} (operacao {1} {2})", total, operador, operando ); }
}
// "Invoker" - Esta classe é o invocador das operações. Instancia a calculadora e um array para guardar operações
class TesteCalculadora
{ // Calculadora
private Calculadora calculadora = new Calculadora();
// Array que guarda as operações
private ArrayList commands = new ArrayList();
// Auxiliar para os for
private int current = 0;
// Aqui temos as operações REDO - Refazer Operação
public void Redo( int vezes )
{ Console.WriteLine( "---- Redo {0} níveis ", vezes ); // realizar operação x vezes
for( int i = 0; i < vezes; i++ )
if( current < commands.Count - 1 )
((Command)commands[ current++ ]).Execute();
}
// e a operação UNDO - Desfazer Operação
public void Undo( int vezes )
{ Console.WriteLine( "---- Undo {0} níveis ", vezes ); // Realizar os Undo's x número de vezes
for( int i = 0; i < vezes; i++ )
if( current > 0 )
((Command)commands[ --current ]).UnExecute();
}
public void Compute( char operador, int operando )
{ // Criar comando e executá-lo
Command command = new CalculatorCommand(calculadora, operador, operando );
command.Execute();
// Adicionar comando à lista de Undo
commands.Add( command );
current++;
}
}
/// <summary>
/// Teste Classe de Teste para testar os conceitos ( Compute: ((10 - 5) * 4) / 2 )
/// </summary>
public class CommandApp
{ public static void Main( string[] args )
{ // Criar novo user
TesteCalculadora testeCalculadora = new TesteCalculadora();
testeCalculadora.Compute( '+', 10 ); // Total 10
testeCalculadora.Compute( '-', 5 ); // Total 5
testeCalculadora.Compute( '*', 4 ); // Total 20
testeCalculadora.Compute( '/', 2 ); // Total 10
// Undo 4 Vezes
testeCalculadora.Undo( 3 );
// Redo 5 Vezes
testeCalculadora.Redo( 2 );
Console.ReadLine() ;
}
}
Nice coding!