190 likes | 311 Views
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;
E N D
Padrão de ProjetoVisitor 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ó)
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
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)
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 CollectingParameter)
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 { privateString name; Wheel(String name) { this.name = name; } String getName() { return this.name; } publicvoidaccept(Visitor visitor) { visitor.visit(this); } } class Engine { publicvoidaccept(Visitor visitor) { visitor.visit(this); } } class Body { publicvoidaccept(Visitor visitor) { visitor.visit(this); } } abstractclass Vehicle { protected Engine engine = new Engine(); protected Body body = new Body(); protected Wheel[] wheels; public Engine getEngine() { returnthis.engine; } public Body getBody() { returnthis.body; } public Wheel[] getWheels() { returnthis.wheels; } publicvoid 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") }; } publicvoid accept(Visitor visitor) { visitor.visitCar(this); } }
Exemplo de Código class PrintVisitor implements Visitor { publicvoid visit(Wheel wheel) { System.out.println("Visiting “ + wheel.getName() + " wheel"); } publicvoid visit(Engine engine) { System.out.println("Visiting engine"); } publicvoid visit(Body body) { System.out.println("Visiting body"); } publicvoid visitVehicle(Vehicle vehicle) { System.out.println("Visiting vehicle"); } publicvoid visitCar(Car car) { System.out.println("Visiting car"); car.getEngine().accept(this); car.getBody().accept(this); for(Wheel wheel : car.getWheels()) { wheel.accept(this); } } } class DoVisitor implements Visitor { publicvoid visit(Wheel wheel) { System.out.println("Steering my wheel"); } publicvoid visit(Engine engine) { System.out.println("Starting my engine"); } publicvoid visit(Body body) { System.out.println("Moving my body"); } publicvoid visitCar(Car car) { System.out.println("Starting my car"); car.getEngine().accept(this); car.getBody().accept(this); for(Wheel wheel : car.getWheels()) { wheel.accept(this); } } publicvoid visitVehicle(Vehicle vehicle) { System.out.println("Starting my vehicle"); } }
Exemplo de Código • publicclass VisitorDemo{ • staticpublicvoid main(String[] args){ • Car car = new Car(); • Visitor printVisitor = new PrintVisitor(); • Visitor doVisitor = new DoVisitor(); • car.accept(printVisitor); • car.accept(doVisitor); • } • }
Fim • Daniel Chevitarese • daniel@chevitarese.com.br • Leandro Alvim • leandrouff@hotmail.com