Mostrando postagens com marcador Padrões de Projeto. Mostrar todas as postagens
Mostrando postagens com marcador Padrões de Projeto. Mostrar todas as postagens

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

quinta-feira, 1 de março de 2012

Pattern: State

Padrão de comportamento que auxilia alterar o comportamento de determinado objeto.

wikipedia
 A classe Context agrega um estado, no qual podem existir vários estados do objeto, e a interface State define um padrão comum para os vários estados. E o estado do objeto Context pode mudar em tempo de execução.



Exemplo: Uma classe carro possui dois estados, estado andando e parado, quando o carro executa o método handle() , ele alterna entre Andando e Parado.

public class Carro {

 private Estado estado;

 public Carro(Estado estado) {
  this.estado = estado;
 }

 public void handle() {
  estado.handle(this);
 }

 public Estado getEstado() {
  return estado;
 }

 public void setEstado(Estado estado) {
  this.estado = estado;
 }

}
 
public interface Estado {
 
 void handle(Carro carro);

}


public class Andando implements Estado {

 @Override
 public void handle(Carro carro) {
  carro.setEstado(new Parado());
 }

}


public class Parado implements Estado{

 @Override
 public void handle(Carro carro) {
  carro.setEstado(new Andando());
 }

}


Utilizando o código criado, iniciamos o carro com um estado e cada vez que chamamos o método handle desse carro, o seu estado é alterado.
 
public static void main(String[] args) {
  
  Carro carro = new Carro(new Parado());
  carro.handle();
  
}

Obrigado

segunda-feira, 27 de fevereiro de 2012

Pattern: Decorator

Um pattern que eu achei muito útil, é o pattern Decorator, com ele podemos adicionar funcionalidades a uma classe sem que ela sofra alguma mudança, ou necessite criar sub-classes.

http://java.dzone.com/articles/design-patterns-decorator


Explicação: Padrão estrutural, no qual você pode adicionar comportamentos e funcionalidades dinamicamente.

Exemplo: Podemos ter vários tipos de emails, no qual dependendo do lugar, podemos enviar sem criptografia ou com criptografia. Adicionando funcionalidade de criptografia no nosso email sem alterar a classe email, pode ser feita com o uso de um decorador. Que no nosso caso, o decorador é EmailCriptografado. A criação do decorator pode ser feita de várias formas, eu simplifiquei um pouco.

 
public interface EmailInterface { 
 public String conteudo();
}

public class Email implements EmailInterface{
 @Override
 public String conteudo() {
  return "";
 }
}


A classe decorator recebe em seu construtor o objeto que se deseja decorar.
 
public class EmailCriptografado implements EmailInterface{
 private EmailInterface email;
 public EmailCriptografado(EmailInterface email){
  this.email = email;
 }
 @Override
 public String conteudo() {
  return email.conteudo();
 }
 public String conteudoCriptografado(){
  String conteudo = email.conteudo();
  //logica para criptografar o email
  return conteudo;
 }
}

Obrigado

sábado, 25 de fevereiro de 2012

Pattern: Visitor

Definição: Padrão de comportamento, provendo funções adicionais a uma classe sem modifica-la em tempo de execução

Imagem do wikipedia


Explicação: O coração do padrão é a interface "Visitor", que permite o Visitador (Classe que implementa Visitor), visitar os elementos que implementam ou estendem a interface/classe Element.

Exemplo: Em um Hospital, existem 3 tipos de profissionais: Médico, Secretária e Enfermeira, e para cada tipo de profissional o hospital define um custo por serviço prestado. O exemplo mostra uma forma de obter o custo total que esse hospital vai ter com todos os seus funcionários.

Primeiro criamos uma interface, no qual será implementada pelas classes que desejamos visitar.
 
public interface Visitable {
 public void accept(Visitor visitor);
}

A implementação do nosso modelo, onde as classes Enfermeiro, Medico e Secreteria irão permitir ser visitados.
 

public class Enfermeiro implements Visitable {

 private double totalServico;

 public Enfermeiro(double totalServico) {
  super();
  this.totalServico = totalServico;
 }

 public double getTotalServico() {
  return totalServico;
 }

 public void setTotalServico(double totalServico) {
  this.totalServico = totalServico;
 }

 public void accept(Visitor visitor) {
  visitor.visitar(this);
 }

}

public class Secretaria implements Visitable {

 private double totalServico;

 public Secretaria(double totalServico) {
  super();
  this.totalServico = totalServico;
 }

 public double getTotalServico() {
  return totalServico;
 }

 public void setTotalServico(double totalServico) {
  this.totalServico = totalServico;
 }

 public void accept(Visitor visitor) {
  visitor.visitar(this);
 }

}


public class Medico implements Visitable {

 private double totalServico;

 public Medico(double totalServico) {
  super();
  this.totalServico = totalServico;
 }

 public double getTotalServico() {
  return totalServico;
 }

 public void setTotalServico(double totalServico) {
  this.totalServico = totalServico;
 }

 public void accept(Visitor visitor) {
  visitor.visitar(this);
 }

}


Para cada tipo de classe concreta, nós precisamos adicionar um método que aceite esta classe.
 
public interface Visitor {
 void visitar(Secretaria secretaria);
 void visitar(Enfermeiro enfermeiro);
 void visitar(Medico medico);
}

Agora podemos calcular o custo total para cada funcionário, sem adicionar nenhuma lógica as nossas classes modelos:
 
public class CalculoTotalServico implements Visitor {

 private double totalServicosPrestados;

 public void visitar(Secretaria secretaria) {
  totalServicosPrestados += secretaria.getTotalServico() + 500;
 }

 public void visitar(Enfermeiro enfermeiro) {
  totalServicosPrestados += enfermeiro.getTotalServico() + 700;
 }

 public void visitar(Medico medico) {
  totalServicosPrestados += medico.getTotalServico() + 1000;
 }

 public double getTotalServicosPrestados() {
  return totalServicosPrestados;
 }

 public void setTotalServicosPrestados(double totalServicosPrestados) {
  this.totalServicosPrestados = totalServicosPrestados;
 }

}

Iterando sobre a lista de objetos, é possivel obter o custo total gerado por seus funcionários:
 
public class Main {

 public static void main(String[] args) {
  CalculoTotalServico calculo = new CalculoTotalServico();
  List< Visitable > lista = getLista();
  for (Visitable visitable : lista) {
   visitable.accept(calculo);
  }  
  System.out.println(calculo.getTotalServicosPrestados());  
 }
 
 public static List< Visitable > getLista(){
  List< Visitable > lista = new ArrayList<>();
  lista.add(new Medico(10000));
  lista.add(new Medico(15000));
  lista.add(new Medico(10000));
  lista.add(new Secretaria(15000));
  lista.add(new Secretaria(10000));
  lista.add(new Enfermeiro(15000));
  lista.add(new Enfermeiro(15000));
  return lista;
 }

}

Visitor é um padrão muito poderoso, que deve ser utilizado com cautela. Obrigado

Pattern: Strategy

Definição: Padrão de comportamente, utilizado quando você precisa mudar em tempo de execução o algoritmo.

Explicação: Você possui várias estratégias, e você quer escolher a estratégia que achar melhor para aquele momento. Criando uma interface e classes que implementam essa interface, é possível fazer isto.

Exemplo:
Você possui uma transportadora, e pode transportar a carga através de um caminhão ou navio, caso seja necessário atravessar um oceano, a melhor estratégia seria ir de navio, caso precise ir de um estado a outro, a melhor estratégia é levar a carga de caminhão. Dependendo do contexto em que se encontra, uma estratégia é melhor que a outra.


 
public interface Transporte {
 void carregar();
}


public class Caminhao implements Transporte{
 public void carregar() {
  System.out.println("Carregar Caminhao");
 }
}


public class Navio implements Transporte{
 public void carregar() {
  System.out.println("Carregar Navio");
 }
}


Agora é possível escolher em tempo de execução o melhor transporte que se deseja executar, sem depender de um ou outro. Obrigado.

quinta-feira, 23 de fevereiro de 2012

Pattern: Template Method

Definição: Padrão de comportamento, é utilizado quando uma parte do algoritmo depende de outros algoritmos, no qual são abstratos, e podem ter várias formas.

Explicação:
Uma classe abstrata possui um método final e executa métodos abstratos que serão implementados nas classes filhas.

Exemplo:
Realizando a compra de um pacote turístico, você possui a execução de um roteiro, no qual será ir para algum lugar, passear neste lugar e voltar para o seu ponto de partida.
A execução do roteiro é a mesma, "ir" "passear" voltar, o que muda é qual o seu meio de transporte para que você possa ir e voltar e aonde você irá passear. A execução do algoritmo que não muda fica definida em um template, que irá chamar os métodos que serão definidos nas classes filhas.
 
public abstract class Viagem {

 public final void viajar() {
  ir();
  passear();
  voltar();
 }

 public abstract void ir();

 public abstract void voltar();

 public abstract void passear();

}

class PacoteA extends Viagem {

 public void ir() {
  System.out.println("Ir de avião");
 }

 public void voltar() {
  System.out.println("Voltar de avião");
 }

 public void passear() {
  System.out.println("Passear em São Paulo");
 }

}

class PacoteB extends Viagem {
 public void ir() {
  System.out.println("Ir de ônibus");
 }

 public void voltar() {
  System.out.println("Voltar de ônibus");
 }

 public void passear() {
  System.out.println("Passear no Rio de Janeiro");
 }
}

class PacoteC extends Viagem {
 public void ir() {
  System.out.println("Ir de ônibus");
 }

 public void voltar() {
  System.out.println("Voltar de ônibus");
 }

 public void passear() {
  System.out.println("Passear na Bahia");
 }
}

Percebam que é um algoritmo bem simples.
Obrigado.