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

Linux
Curso Java
Papers Java
Database
Hardware
Informática
Gestão de TI
Diversão
Download
Potions
Homepage
Blog
Facebook
Youtube
Twitter
Linubr.org
Nenhum comentário:
Postar um comentário