domingo, 4 de março de 2012

Pattern: Chain of responsibility

Padrão de comportamento.

Java Dzone (2)


GOF: Avoid coupling the sender of a request to its receiver by giving more than one
object a chance to handle the request. Chain the receiving objects and pass the
request along the chain until an object handles it.


Tradução livre: Evitar acoplar o enviador da requisição com o recebedor (objeto que irá tratar a requisição) , dando a oportunidade de mais de um objeto tratar esta requisição. Encadeie os recebedores e passe a requisição por essa cadeia até que algum recebedor trate.


Quando utilizar?
 - Quando você deseja que a requisição seja interceptada e tratada por mais de um objeto, e estes objetos sejam escolhidos em tempo de execução.

Consequências:
- Reduz acoplamento: Não acopla o enviador com o recebedor. O recebedor não sabe da existência de outros recebedores.
- Adiciona flexibilidade: Pode-se adicionar recebedores e retirar recebedores em tmepo de execução.
- Não há garantia que algum recebedor intercepte algum objeto.

Geralmente este padrão é utilizado com o padrão Composite.

Exemplo:
Utilizando-se do exemplo de Email do Java Dzone (2),  vou exemplificar o uso deste padrão. 

O sistema irá receber um email e dependendo do email, ele deverá passar um tratamento. No caso deste exemplo, o "tratamento" é simplismente um print na tela.


Nossa classe Email, que iŕa conter o email propriamente dito.
public class Email {

 private String from;

 public String getFrom() {
  return from;
 }

 public void setFrom(String from) {
  this.from = from;
 }
 
}

A interface EmailHandler, define dois métodos que as classes concretas deverão implementar. No caso o método setNext, indica a próxima classe que deverá tratar a requisição, criando assim uma cadeia de objetos.
public interface EmailHandler {
 
 public void setNext(EmailHandler next);
 
 public void handleRequest(Email email);

}

A classe AbstractEmailHandler implementa a classe EmailHandle. O método handleRequest irá verificar se o email é do tipo que deve ser interceptado, caso for, o método doHandle fará o tratamento, caso não for, passa para o próximo objeto da cadeia se existir, caso não exista a interceptação acaba. Cuidado que seu objeto no final pode não ser interceptado.
public abstract class AbstractEmailHandler implements EmailHandler{
 
 private EmailHandler next;
 
 public final void setNext(EmailHandler next){
  this.next = next;
 }
 
 public final void handleRequest(Email email){
  if(accept(email)){
   doHandle(email);
  }else if(this.next != null){
   this.next.handleRequest(email);
  }
 }
 
 public abstract boolean accept(Email email);
 public abstract void doHandle(Email email);

}

Classes concretas que estendem AbstractEmailHandler
public class GmailHandler extends AbstractEmailHandler{

 @Override
 public boolean accept(Email email) {
  return email.getFrom().endsWith("@gmail.com");
 }

 @Override
 public void doHandle(Email email) {
  System.out.println("Email Gmail = " + email.getFrom());
 }

}
public class HotmailHandler extends AbstractEmailHandler{

 @Override
 public boolean accept(Email email) {
  return email.getFrom().endsWith("@hotmail.com");
 }

 @Override
 public void doHandle(Email email) {
  System.out.println("Email Hotmail = " + email.getFrom());
 }

}

EmailProcessor mantém a referência ao primeiro adicionado para ser chamado quando for interceptar algum email, assim passo por uma cadeia de interceptadores.
public class EmailProcessor {
 
 private EmailHandler successor;
 private EmailHandler first;
 
 public EmailProcessor(){
 }
 
 public void addEmailHandler(EmailHandler emailHandler){
  if(this.first == null){
   this.first = emailHandler;
  }else{
   this.successor.setNext(emailHandler); 
  }
  this.successor = emailHandler;
 }
 
 public void handleRequest(Email email){
  first.handleRequest(email);
 }
 
}

Utilizando do EmailProcessor é enviado um email para tratamento. Dois handlers são adicionados, na forma de interceptar emails Gmail e Hotmail.
public class EmailClient {
 
 
 public static void main(String... args){
  EmailProcessor emailProcessor = new EmailProcessor();
  emailProcessor.addEmailHandler(new GmailHandler());
  emailProcessor.addEmailHandler(new HotmailHandler());
  Email email = new Email();
  email.setFrom("diegogusava@gmail.com");
  emailProcessor.handleRequest(email);
 }

}
Imprime: Email Gmail = diegogusava@gmail.com

Bibliografia:
1 - http://refcardz.dzone.com/refcardz/design-patterns
2 - http://java.dzone.com/articles/design-patterns-uncovered-chain-of-responsibility
3 - http://www.k19.com.br/downloads/apostilas-java/k19-k51-design-patterns-em-java
4 - http://www.slideshare.net/vsenger/33-design-patterns-com-java/download

Nenhum comentário:

Postar um comentário