Command
Resumo
O Padrão Command encapsula uma solicitação como um objeto, o que lhe permite parametrizar outros objetos com diferentes solicitações, enfileirar ou registrar solicitações e implementar recursos de cancelamento de operações.
A principal motivação do uso do padrão Command é que algumas vezes é necessário emitir solicitações para objetos sem nada saber sobre a operação que está sendo solicitada ou sobre seu receptor .
Como exemplos de uso do padrão temos menus e controles, que são aplicações que possuem apenas comandos (ações) para serem executados através deles.
O padrão
O padrão Command, também conhecido por Action ou Transaction, é um padrão simples e muito utilizado. Porém ele possui alguns detalhes importantes que precisam ser notados, caso contrário sua implementação pode não trazer tanta reutilização.
O Command tem como objetivo encapsular uma solicitação como um objeto, o que permite parametrizar outros objetos com diferentes solicitações, enfileirar ou registrar solicitações e implementar recursos de cancelamento de operações (desfazer). Ou seja, o objetivo do padrão é transformar um método de uma classe em um objeto, o qual pode executar a ação deste método.
O livro Padrões de Projeto de Erich Gamma diz que a principal motivação do Command é que algumas vezes é necessário emitir solicitações para objetos sem nada saber sobre a operação que está sendo solicitada ou sobre seu receptor. Exemplificando o que o livro diz, imagine um portão eletrônico que você queira abrir, não é necessário saber como funciona o mecanismo que faz o portão abrir ou de que o portão é feito, você apenas quer abrir o portão e por isso aperta um botão que faz ele abrir.
Na figura 1 é apresentado o diagrama de classes do Padrão Command.
Figura 1 – Diagrama de Classes
Participantes
- Command: Declara uma interface para a execução de uma operação.
- ConcreteCommand: Define uma vinculação entre um objeto, um Receiver e uma ação. E também implementa “execute” através da invocação da operação correspondente no Receiver.
- Client: Cria um objeto ConcreteCommand e estabelece o seu receptor.
- Invoker: Solicita ao Command a execução da solicitação
- Receiver: Sabe como executar as operações associadas a uma solicitação. Qualquer classe pode funcionar como um Receiver.
Visto o diagrama de classes e seus participantes agora vamos entender a implementação com um exemplo de um Portão Eletrônico que possui um controle que faz o portão abrir e fechar. Na figura 2 está a implementação do Portão.
Figura 2 – Classe Portao
A classe portão possui um atributo estado, onde quando for igual a 0, o portão está aberto, enquanto for igual a 1 o portão está fechado. A classe também possui o método abrir que abre o portão e o método fechar que fecha o portão.
Figura 3 – Interface Command
Na figura 3 está representado a interface Command, que possui o método execute e também o método undo, o qual é opcional, porque nem todas as ações possibilitam uma operação de desfazer.
Figura 4 – Classe AbrirCommand
Na figura 4 é apresentado a classe AbrirCommand, que é um ConcreteCommand, sua funcionalidade é fazer um portão abrir através do método execute. Para isto, a classe traz um atributo do tipo portão, que precisa ser “setado“ através do construtor. Além de abrir o portão essa classe também possibilita desfazer a operação de abrir, através do método undo que faz o oposto do execute, fechando o portão.
Figura 5 – Classe Controle
Na figura 5 é mostrado a classe Controle que é o Invoker, ela armazena Commands e chama o método execute do command. Além disto, ela possui um outro atributo command (ultimoCommand) que armazena o ultimo command que foi usado, através disso, o controle possui um método desfazer que chama o método undo do ultimo command utilizado.
A principal consequência do Command é que ele desacopla o objeto que invoca a operação daquele que sabe como executá-la. Ao visualizar o diagrama de sequência na figura 2 ficará mais claro como isto ocorre.
Figura 6 – Diagrama de Sequência
Primeiro o Client cria um novo Command especificando seu Receiver, em seguida este Command é armazenado em um Invoker. O Invoker quando quer chamar a ação do Receiver, usa o método execute do Command que por sua vez chama a ação do Receiver. Deste modo o Invoker não conhece como funciona a ação e também não conhece o Receiver.
Para conhecer mais sobre o padrão recomendo que baixem o slide disponível, olhem o exemplo implementado e que façam a atividade prática proposta. Também é interessante ler as referências que foram utilizadas para este trabalho.
Referências
- GAMMA, Erich; HELM; Richard; JOHSON, Ralph; VLISSIDES, John – Padrões de Projeto – Soluções reutilizáveis de software orientados a objeto .
- FREEMAN, Eric – Use a cabeça!: Padrões de Projetos (Design Patterns).
Por: Luiz Serra e Matheus Matos.