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

Nenhum comentário:

Postar um comentário