pontoNETpt
A comunidade PontoNetPT está direccionada a todos os programadores que trabalhem com a plataforma .NET.
Command Behavioural Pattern

Quem já quis implementar acções tais como Undo e Redo de operações nos seus componentes e acabou embrulhado? (ehhrrrr,  EU!)

O Command pattern é um dos mais poderosos e utilizados padrões de comportamento que permitem uma flexibilidade enorme para dotar componentes de capacidades tais como o Undo/Redo de operações, queue ou log de pedidos ou parametrizar clientes com diferentes pedidos.

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!

Posted 27-9-2005 10:31 por Rui Claro

Add a Comment

(requerido)  
(opcional)
(requerido)  
Remember Me?
If you can't read this number refresh your screen
Enter the numbers above:  
Powered by Community Server (Commercial Edition), by Telligent Systems