---
title: "Visitor e Double Dispatch"
type: "design-pattern"
slug: "visitor-double-dispatch"
url: "http://localhost:3000/pt-br/design-patterns/visitor-double-dispatch.md"
---
# Visitor e Double Dispatch

Vamos dar uma olhada na seguinte hierarquia de classes de formas geométricas (cuidado, é pseudocódigo):

interface Graphic is
    method draw()

class Shape implements Graphic is
    field id
    method draw()
    // ...

class Dot extends Shape is
    field x, y
    method draw()
    // ...

class Circle extends Dot is
    field radius
    method draw()
    // ...

class Rectangle extends Shape is
    field width, height
    method draw()
    // ...

class CompoundGraphic implements Graphic is
    field children: array of Graphic
    method draw()
    // ...

O código funciona bem e a aplicação está em produção. Mas um dia você decidiu criar um recurso de exportação. O código de exportação ficaria deslocado se colocado nessas classes. Então, em vez de adicionar a exportação a todas as classes dessa hierarquia, você decidiu criar uma nova classe, externa à hierarquia, e colocar toda a lógica de exportação dentro dela. A classe teria métodos para exportar o estado público de cada objeto em strings XML:

class Exporter is
    method export(s: Shape) is
        print("Exporting shape")
    method export(d: Dot)
        print("Exporting dot")
    method export(c: Circle)
        print("Exporting circle")
    method export(r: Rectangle)
        print("Exporting rectangle")
    method export(cs: CompoundGraphic)
        print("Exporting compound")

O código parece bom, mas vamos testá-lo:

class App() is
    method export(shape: Shape) is
        Exporter exporter = new Exporter()
        exporter.export(shape);

app.export(new Circle());
// Infelizmente, isso vai imprimir "Exporting shape".

Espere! Por quê?!

## Pensando como um compilador

Observação: as informações a seguir são verdadeiras para a maioria das linguagens de programação orientadas a objetos modernas (Java, C#, PHP e outras).

### Vinculação tardia/dinâmica

Imagine que você é um compilador. Você tem que decidir como compilar o código a seguir:

method drawShape(shape: Shape) is
    shape.draw();

Vejamos... o método `draw` está definido na classe `Shape`. Espere um segundo, mas também há quatro subclasses que sobrescrevem esse método. Conseguimos decidir com segurança qual das implementações chamar aqui? Não parece. A única forma de saber com certeza é executar o programa e verificar a classe de um objeto passado para o método. A única coisa que sabemos com certeza é que o objeto **terá** uma implementação do método `draw`.

Portanto, o código de máquina resultante verificará a classe do objeto passado para o parâmetro `shape` e escolherá a implementação de `draw` da classe apropriada.

Essa verificação dinâmica de tipo é chamada de vinculação tardia (ou dinâmica):

* **Tardia**, porque vinculamos o objeto e sua implementação após a compilação, em tempo de execução.
* **Dinâmica**, porque cada novo objeto pode precisar ser vinculado a uma implementação diferente.

### Vinculação inicial/estática

Agora, vamos “compilar” o código a seguir:

method exportShape(shape: Shape) is
    Exporter exporter = new Exporter()
    exporter.export(shape);

A segunda linha está clara: a classe `Exporter` não tem um construtor personalizado, então simplesmente instanciamos um objeto. E quanto à chamada `export`? O `Exporter` tem cinco métodos com o mesmo nome que diferem nos tipos de parâmetro. Qual deles chamar? Parece que vamos precisar de uma vinculação dinâmica aqui também.

Mas há outro problema. E se houver uma classe de forma que não tenha um método `export` apropriado na classe `Exporter`? Por exemplo, um objeto `Ellipse`. O compilador não consegue garantir que o método sobrecarregado apropriado exista, ao contrário dos métodos sobrescritos. Surge uma situação ambígua que o compilador não pode permitir.

Por isso, os desenvolvedores de compiladores seguem um caminho seguro e usam a vinculação inicial (ou estática) para métodos sobrecarregados:

* **Inicial** porque acontece em tempo de compilação, antes de o programa ser iniciado.
* **Estática** porque não pode ser alterada em tempo de execução.

Voltemos ao nosso exemplo. Temos certeza de que o argumento recebido será da hierarquia `Shape`: ou a classe `Shape` ou uma de suas subclasses. Também sabemos que a classe `Exporter` tem uma implementação básica da exportação que suporta a classe `Shape`: `export(s: Shape)`.

Essa é a única implementação que pode ser vinculada com segurança a um dado código sem tornar as coisas ambíguas. É por isso que, mesmo que passemos um objeto `Rectangle` para `exportShape`, o exportador ainda chamará um método `export(s: Shape)`.

## Double dispatch

**Double dispatch** (despacho duplo) é um truque que permite usar vinculação dinâmica junto com métodos sobrecarregados. Veja como isso é feito:

class Visitor is
    method visit(s: Shape) is
        print("Visited shape")
    method visit(d: Dot)
        print("Visited dot")

interface Graphic is
    method accept(v: Visitor)

class Shape implements Graphic is
    method accept(v: Visitor)
        // O compilador sabe com certeza que `this` é um `Shape`.
        // O que significa que `visit(s: Shape)` pode ser chamado com segurança.
        v.visit(this)

class Dot extends Shape is
    method accept(v: Visitor)
        // O compilador sabe que `this` é um `Dot`.
        // O que significa que `visit(s: Dot)` pode ser chamado com segurança.
        v.visit(this)

Visitor v = new Visitor();
Graphic g = new Dot();

// O método `accept` é sobrescrito, não sobrecarregado. O compilador o vincula
// dinamicamente. Portanto, o `accept` será executado em uma classe que
// corresponde a um objeto que chama um método (no nosso caso, a classe `Dot`).
g.accept(v);

// Saída: "Visited dot"

### Posfácio

Embora o padrão [Visitor](/pt-br/design-patterns/visitor) seja construído sobre o princípio do double dispatch, esse não é seu propósito principal. O Visitor permite adicionar operações “externas” a toda uma hierarquia de classes sem alterar o código existente dessas classes.
