Client
O cliente realiza a chamada (instancia) dos métodos do Invoker.
Invoker
Ele será o beneficiado direto do recurso. Invoker possui um atributo de Command (existem variações, porém vou explicar um caso geral). No constructor de Invoker, o valor desse atributo será definido. Quando Invoker for instanciado, ele deverá conter algum objeto que implemente de forma concreta a interface Command. Além disso, Invoker também possui um método que executa o método execute() de Command, porém ele não sabe o que será executado. Esse é o ponto forte desse padrão. Invoker precisa executar alguma coisa no qual não conhece e não possui acoplamento. Veremos um exemplo prático.
Receiver
Em termos gerais, esta é uma instância da classe que contém a implementação da operação. Esse é o objeto que possui o código da operação em si. Qualquer classe pode funcionar como um Receiver. Na prática, uma classe (ConcreteCommand) implementará a interface Command e, por consequência, implementará o método execute(). Nesse método será trabalhado algum comportamento de Receiver.
Command
Interface que implementa a assinatura dos métodos utilizados. No mínimo ela deverá implementar um método chamado execute().
ConcreteCommand
Esta classe implementa a interface Command e define o método execute(). Deve-se atentar que o comportamento do comando tem origem em Receiver.
Para implementar um Command, precisamos de:
- Criar uma interface chamada Command com o método execute()
-
Criar a classe Receiver que implementa os comportamentos reais
- Criar a classe que implementa Command, encapsula os métodos de Receiver no método execute()
- Criar a classe Invoker, que possui um elemento Command e métodos que invocam execute()
- Criar a classe Client que trabalha com as opções de Invoker
Para melhor exemplificar a implementação, observe o diagrama abaixo:

Como mostrado no diagrama de classe acima, a interface Command define o protótipo do comando execute(). Esse método é criado na classe ConcreteCommand que executa o método action() do Receiver. Observe ainda que Invoker é constituído por Command. Ao definirmos uma ConcreteCommand no atributo command de Invoker, estaremos associando esse objeto a um comportamento no qual ele não conhece.
Vamos agora a um exemplo prático da utilização deste padrão.
Exemplo prático
Imagine a seguinte situação: existem duas equipes de desenvolvimento de um projeto. A equipe 1 é responsável pela camada de negócios. A equipe 2 fará o desenvolvimento da camada de aplicação (interface com usuário). A equipe 2 irá desenvolver uma Frame com 2 botões. A questão é a seguinte: O que ocorre quando o botão for acionado? A equipe 2 não sabe! Se botão possuir um atributo da interface Command, ele poderá executar operações diferentes de acordo com o comportamento criado nas classes concretas de Command. Da mesma forma, a equipe 1 não sabe a partir de qual botão serão acionados os métodos de negócio. O que ela faz é criar um encapsulamento das operações como uma implementação concreta da interface Command. Quando a classe Client (um dos elementos do padrão Command) for criada, a associação entre esses comportamentos será definida.

Vamos ao código:
A codificação da interface Command é mostrada abaixo.
Command.java
package engine;
public interface Command {
public void execute();
}
Veremos agora a classe Button, referente ao Invoker.
Button.java
package engine;
public class Button {
private Command command;
public Button(Command command) {
this.command = command;
}
public void clicked() {
this.command.execute();
}
}
Veja que esta classe possui um atributo de Command que será definido na criação do objeto. Ao executar clicked(), o método execute() será acionado. Isso faz com que o botão não tenha conhecimento da ação efetuada em seu clique. Vamos ver agora a classe associada ao Receiver, chamada Business. Em nosso estudo, a equipe 2 foi responsável pela criação de Button.java.
Business.java
package engine;
public class Business {
public void findData() {
System.out.println( "Procurando dados!" );
}
public void saveData() {
System.out.println( "Salvando dados!" );
}
}
Nessa classe os métodos de negócio são definidos. Em nosso exemplo, a equipe 1 foi responsável pela criação desta classe. Agora esses comportamentos precisam ser encapsulados em objetos. Abaixo temos as classes FindData e SaveData, ambos criados pela equipe 1.
FindData.java
package engine;
public class FindData implements Command {
private Business receiver;
public FindData(Business receiver) {
this.receiver = receiver;
}
public void execute() {
this.receiver.findData();
}
}
Observe que o método real findData() de Business foi chamado em execute().
SaveData.java
package engine;
public class SaveData implements Command {
private Business receiver;
public SaveData(Business receiver) {
this.receiver = receiver;
}
public void execute() {
this.receiver.saveData();
}
}
De forma semelhante, execute() acionará o método saveData() de Business. Por fim, veremos agora o objeto Frame. Este será responsável pela configuração do comportamento dos botões. Ele é associado ao objeto Client do pattern Command. Veja seu código abaixo:
package engine;
public class Frame {
private Business receiver;
public Frame(Business receiver) {
this.receiver = receiver;
}
public Business getReceiver() {
return this.receiver;
}
public static void main(String args[]) {
Frame frame = new Frame( new Business() );
Command findData = new FindData( frame.getReceiver() );
Command saveData = new SaveData( frame.getReceiver() );
Button findButton = new Button( findData );
Button saveButton = new Button( saveData );
findButton.clicked();
saveButton.clicked();
}
}
Vamos entender o que ocorre. Frame é uma interface com usuário. Quando os botões foram criados (codificação da classe Button), suas ações ainda não eram previstas - ou seja, um botão é genérico. Ao conter uma interface Command, o Button poderá executar o método de acordo com o comportamento definido nas classes concretas FindData e SaveData. Veja no código anterior que são criados dois botões. O primeiro deles, quando clicado, executa o comportamento FindData - que na verdade é a operação findData de Business encapsulada num objeto. O mesmo ocorre para saveButton.
Conclusões
Ao utilizar padrões como esse, estamos favorecendo atributos como escalabilidade da aplicação. O reaproveitamento de código é facilitado e existe também ganho de desenvolvimento levando em consideração o tempo. Por fim, é uma boa prática de programação a utilização de patterns como esse.
Referências
http://www.dotnetraptors.com.br/start/artigos/artigos_open_space/5679.aspx
http://en.wikipedia.org/wiki/Command_pattern
http://sourcemaking.com/design_patterns/command
http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/command.htm
"Esforce-se para viver ou esforce-se para morrer!" Stephen King (livro Quatro Estações)
Espero ter ajudado!
Guilherme Pontes
Nenhum comentário:
Postar um comentário