Padrão de Projeto
Visitor
Daniel Chevitarese
Leandro Alvim
Introdução
•
•
•
•
•
•
•
•
Propósito do Padrão
Motivação
Aplicação
Estrutura
Participantes
Colaborações
Conseqüências
Exemplo de Código
Propósito do Padrão
• Representação de operações;
• Possibilitar a adição de operações
especializadas de forma que não haja a
necessidade da modificação de diversos
elementos da estrutura
Motivação
• Problema
– Representar operações especializadas que devem ser
executadas sobre os elementos de uma estrutura
• Solução usual
– Implementar operação especializada em cada elemento da
estrutura
• Solução por padrão (Visitor)
– Elaboração de um padrão que possibilite a adição de novas
operações especializadas de forma que não haja a
necessidade da modificação de diversos elementos da
estrutura
– Como ?
• Separação do comportamento da estrutura
Motivação
• Exemplo de um Compilador
– Representação de um programa
• Árvore sintática abstrata
– A árvore possui diferentes tipos de nós
» Operadores;
» Variáveis;
» Expressões matemáticas;
– Exemplo de operações de um compilador na árvore
sintática abstrata
•
•
•
•
Formatação;
Verificação de tipos;
Verificar se todas as variáveis estão definidas;
Geração de código
Motivação
• Problema
– As operações podem necessitar tratar cada tipo de nó de maneira diferente
• Solução usual
– Definição da operação na classe que a utiliza;
– Desvantagens
• Inclusão de novas operações requer a mudança de todas as classes de nós;
• Poluição das classes com muitas operações
– Mistura de verificação de tipos com formatação
Motivação
• Solução por padrão
– Encapsular a operação em um objeto em
separado (Visitor)
– Algoritmo do Visitor
• O objeto Visitor percorre os elementos da árvore;
• Se um nó da árvore “aceita” um visitor então
– chama um método seu que inclui o tipo do nó como
argumento;
– Executa a operação para aquele nó (a operação que
costumava estar na classe nó)
Motivação
Aplicação
• Quando se têm muitas classes de objetos com interfaces
distintas e quer-se realizar operações nesses objetos que
dependam das suas classes concretas;
• Quando a estrutura de objetos é utilizada por diversas
aplicações
– Cada aplicação com seu Visitor apropriado;
– Possibilidade de reuso de Visitors comuns;
• Quando se quer evitar a poluição da classe com operações
não-relacionadas e que são utilizadas em vários objetos;
• Quando a estrutura que define os objetos é praticamente
estática e as operações realizadas neles estão em constante
mudança
– A situação inversa não se aplica
Estrutura
Participantes
• Visitor
– Declara uma operação de visita (Visit) para cada classe a
ser visitada (ConcreteElement);
– Identifica a classe ConcreteElement através do nome e
assinatura da operação Visit
• ConcreteVisitor
– Implementa cada operação de visita declarada pelo Visitor;
– Cada operação implementará um algoritmo que receberá
o seu contexto e estado de atuação
• Element
– Define a operação Accept que recebe um Visitor como
argumento
Participantes
• ConcreteElement
– Implementa a operação Accept que recebe um
Visitor como argumento
• ObjectStructure
– Pode enumerar diversos Elements;
– Pode prover uma interface que permita o Visitor
visitar os seus Elements associados;
– Pode ser um composite ou uma coleção (lista ou
conjunto)
Colaborações
Conseqüências – Vantagens
• Facilidade na adição de operações
– Com as operações concentradas no Visitor, não há necessidade de
implementação da operação em diversas classes;
– Para uma nova funcionalidade, simplesmente adicione um novo
Visitor
• Agrupamento lógico-comportamental de operações
– Comportamentos não ficam espalhados e sim agrupados por Visitor;
– Comportamentos não relacionados ficam em Visitors distintos
• Visitação de objetos pertencentes a hierarquias distintas
– Note que um Iterador não conseguiria esta façanha
• Acúmulo de estados
– A não-utilização do Visitor, força o desenvolvedor a guardar o estado
em um objeto e passando por parâmetro (padrão Collecting
Parameter)
Conseqüências – Desvantagens
• A adição de classes ConcreteElement pode ser
trabalhosa
– Cada ConcreteVisitor tem que ser mudado para
adicionar a nova operação
– Dependência entre Visitante e Visitado
• Quebra do encapsulamento
– Como a operação encontra-se dentro de um
Visitor e não em um ConcreteElement, este pode
necessitar expor uma maior quantidade de
interfaces para que o Visitor o acesse
Exemplo de Código
interface Visitor {
void visit(Wheel wheel);
void visit(Engine engine);
void visit(Body body);
void visitCar(Car car);
void visitVehicle(Vehicle vehicle);
}
class Wheel {
private String name;
Wheel(String name) {
this.name = name;
}
String getName() {
return this.name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Engine {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Body {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
abstract class Vehicle {
protected Engine engine = new Engine();
protected Body
body
= new Body();
protected Wheel[] wheels;
public Engine getEngine() {
return this.engine;
}
public Body getBody() {
return this.body;
}
public Wheel[] getWheels() {
return this.wheels;
}
public void accept(Visitor visitor) {
visitor.visitVehicle(this);
}
}
class Car extends Vehicle {
public Car() {
super();
this.wheels = new Wheel[]{
new Wheel("front left"),
new Wheel("front right"),
new Wheel("back left"),
new Wheel("back right")
};
}
public void accept(Visitor visitor) {
visitor.visitCar(this);
}
}
Exemplo de Código
class PrintVisitor implements Visitor {
class DoVisitor implements Visitor {
public void visit(Wheel wheel) {
public void visit(Wheel wheel) {
System.out.println("Steering my wheel");
System.out.println("Visiting “
}
+ wheel.getName()
public void visit(Engine engine) {
+ " wheel");
System.out.println("Starting my engine");
}
}
public void visit(Engine engine) {
public void visit(Body body) {
System.out.println("Visiting engine");
System.out.println("Moving my body");
}
}
public void visit(Body body) {
public void visitCar(Car car) {
System.out.println("Visiting body");
System.out.println("Starting my car");
}
car.getEngine().accept(this);
car.getBody().accept(this);
public void visitVehicle(Vehicle vehicle) {
for(Wheel wheel : car.getWheels()) {
System.out.println("Visiting vehicle");
wheel.accept(this);
}
}
public void visitCar(Car car) {
}
System.out.println("Visiting car");
public void visitVehicle(Vehicle vehicle) {
car.getEngine().accept(this);
System.out.println("Starting my vehicle");
car.getBody().accept(this);
}
for(Wheel wheel : car.getWheels()) {
}
wheel.accept(this);
}
}
}
Exemplo de Código
public class VisitorDemo{
static public void main(String[] args){
Car car = new Car();
Visitor printVisitor = new PrintVisitor();
Visitor doVisitor = new DoVisitor();
car.accept(printVisitor);
car.accept(doVisitor);
}
}
Fim
• Daniel Chevitarese
– [email protected]
• Leandro Alvim
– [email protected]
Download

Slides - (LES) da PUC-Rio