Padrão de visitante
A padrão de visitante é um padrão de design de software que separa o algoritmo da estrutura do objeto. Devido a essa separação, novas operações podem ser adicionadas às estruturas de objetos existentes sem modificar as estruturas. É uma maneira de seguir o princípio aberto/fechado na programação orientada a objetos e engenharia de software.
Em essência, o visitante permite adicionar novas funções virtuais a uma família de aulas, sem modificar as classes. Em vez disso, é criada uma classe de visitantes que implementa todas as especializações apropriadas da função virtual. O visitante assume a referência da instância como entrada e implementa a meta por meio de despacho duplo.
Linguagens de programação com tipos de soma e correspondência de padrões Evite muitos dos benefícios do padrão do visitante, pois a classe de visitantes é capaz de ramificar facilmente o tipo de objeto e gerar um erro do compilador se um novo tipo de objeto for definido O visitante ainda não lida.
Visão geral
O visitante O padrão de design é um dos vinte e três gangues conhecidos de quatro padrões de design que descrevem como resolver problemas de design recorrentes para projetar software flexível e reutilizável, ou seja, ou seja, Objetos mais fáceis de implementar, alterar, testar e reutilizar.
Que problemas o padrão de design do visitante pode resolver?
- Deve ser possível definir uma nova operação para (alguns) classes de uma estrutura de objeto sem alterar as classes.
Quando novas operações são necessárias com frequência e a estrutura do objeto consiste em muitas classes não relacionadas, É inflexível para adicionar novas subclasses cada vez que uma nova operação é necessária Porque "[..] distribuir todas essas operações nas várias classes de nós leva a um sistema que é difícil de entender, manter e mudar. "
Que solução o padrão de design do visitante descreve?
- Defina um objeto separado (visitante) que implemente uma operação a ser realizada em elementos de uma estrutura de objeto.
- Os clientes atravessam a estrutura do objeto e chamam de operação de envio aceitar (visitante) em um elemento — que "dispatches" (delegados) o pedido ao "objeto visitante aceite". O objeto visitante então executa a operação no elemento ("visita o elemento").
Isso torna possível criar novas operações independentemente das classes de uma estrutura de objeto Adicionando novos objetos de visitante.
Veja também a classe UML e o diagrama de sequência abaixo.
Definição
A gangue de quatro define o visitante como:
Representar[ing] uma operação a ser realizada em elementos de uma estrutura de objeto. O visitante permite definir uma nova operação sem alterar as classes dos elementos em que opera.
A natureza do visitante o torna um padrão ideal para se conectar às APIs públicas, permitindo assim que seus clientes executem operações em uma classe usando a " visitando " classe sem precisar modificar a fonte.
Vantagens
mover operações para as aulas de visitantes é benéfico quando
- muitas operações não relacionadas em uma estrutura de objeto são necessárias,
- as classes que compõem a estrutura do objeto são conhecidas e não esperadas mudar,
- novas operações precisam ser adicionadas com freqüência,
- um algoritmo envolve várias classes da estrutura do objeto, mas é desejado gerenciá-lo em um único local,
- um algoritmo precisa trabalhar em várias hierarquias de classe independentes.
Uma desvantagem desse padrão, no entanto, é que ele torna as extensões da hierarquia de classes mais difíceis, pois novas classes normalmente exigem um novo método Visite
a ser adicionado a cada visitante.
APLICAÇÃO
Considere o design de um sistema 2D de design auxiliado por computador (CAD). Na sua essência, existem vários tipos para representar formas geométricas básicas, como círculos, linhas e arcos. As entidades são ordenadas em camadas e, no topo da hierarquia de tipos, está o desenho, que é simplesmente uma lista de camadas, além de algumas propriedades adicionais.
Uma operação fundamental nesse tipo hierarquia está salvando um desenho no formato de arquivo nativo do sistema. À primeira vista, pode parecer aceitável adicionar métodos de salvamento local a todos os tipos da hierarquia. Mas também é útil poder salvar desenhos em outros formatos de arquivo. Adicionar cada vez mais métodos para salvar em muitos formatos de arquivo diferentes logo agrada a estrutura de dados geométricos original relativamente pura.
Uma maneira ingênua de resolver isso seria manter funções separadas para cada formato de arquivo. Essa função salvadora levaria um desenho como entrada, a atravessaria e codificaria esse formato de arquivo específico. Como isso é feito para cada formato adicional adicional, a duplicação entre as funções se acumula. Por exemplo, salvar uma forma de círculo em um formato raster requer código muito semelhante, independentemente da forma de varredura específica e é diferente de outras formas primitivas. O caso de outras formas primitivas, como linhas e polígonos, é semelhante. Assim, o código se torna um grande loop externo atravessando os objetos, com uma grande árvore de decisão dentro do loop consultando o tipo de objeto. Outro problema com essa abordagem é que é muito fácil perder uma forma em um ou mais poupadores, ou uma nova forma primitiva é introduzida, mas a rotina de salvamento é implementada apenas para um tipo de arquivo e não para outros, levando à extensão e manutenção de código e manutenção problemas. À medida que as versões do mesmo arquivo cresce, fica mais complicado para mantê -lo.
Em vez disso, o padrão do visitante pode ser aplicado. Ele codifica a operação lógica (isto é, salvar (image_tree)) em toda a hierarquia em uma classe (ou seja, economizador) que implementa os métodos comuns para atravessar a árvore e descrever métodos auxiliares virtuais (ou seja, salvar_circle, salvar_square, etc.) a serem implementados para formatar comportamentos específicos. No caso do exemplo CAD, esses comportamentos específicos de formato seriam implementados por uma subclasse do visitante (ou seja, Saverpng). Como tal, toda a duplicação de verificações de tipo e etapas de travessia é removida. Além disso, o compilador agora reclama se uma forma é omitida, pois agora é esperada pela função Common Base Traversal/Salvar.
Loops de iteração
O padrão do visitante pode ser usado para iteração sobre estruturas de dados semelhantes a contêineres, assim como o padrão do iterador, mas com funcionalidade limitada. Por exemplo, a iteração sobre uma estrutura de diretório pode ser implementada por uma classe de função em vez de um padrão de loop mais convencional. Isso permitiria derivar várias informações úteis do conteúdo dos diretórios, implementando uma funcionalidade de visitante para cada item e reutilizando o código de iteração. É amplamente empregado em sistemas SmallTalk e também pode ser encontrado no C ++. Uma desvantagem dessa abordagem, no entanto, é que você não pode sair do loop facilmente ou iterar simultaneamente (em paralelo, isto é, atravessar dois recipientes ao mesmo tempo por um único i
variável). Este último exigiria a gravação de funcionalidades adicionais para um visitante suportar esses recursos.
estrutura
Classe UML e diagrama de sequência

No diagrama da classe UML acima, a classe elemento
não implementa diretamente uma nova operação.
Em vez disso, elemento
implementa uma operação de despacho aceitar (visitante)
que " despacho " (delegados) uma solicitação ao objeto de visitante aceito " ( visitor.VisiteLementA (this)
). A classe visitante1
implementa a operação ( visitElementA (e: elemento)
).
ElementB
Em seguida, implementa Aceite (visitante)
Despactando para visitor.VisitelementB (this)
. A classe visitante1
implementa a operação ( visitElementB (e: elementb)
).
O diagrama de sequência UML
Mostra as interações de tempo de execução: o objeto cliente
atravessa os elementos de uma estrutura de objeto ( elemento, elementb
) e chamadas aceitar (visitante)
on-line cada elemento.
Primeiro, o cliente
CHAMANCIA Aceitar (visitante)
on
Elementarta
, que chama visitElementA (this)
no objeto aceito .
O elemento em si ( isto
) é passado para o visitante
para que
pode visitar " Elementarta
(ligue para Operaçãoa ()
).
Posteriormente, o cliente
CHAMANCIA Aceitar (Visitante)
ON
ElementB
, que chama visitElementb (this)
no visitante
que " visitas " ElementB
(chamadas OperaçãoB ()
).
Diagrama de classe


Detalhes
O padrão do visitante requer uma linguagem de programação que suporta despacho único, como idiomas comuns orientados a objetos (como C ++, Java, Smalltalk, Objective-C, Swift, JavaScript, Python e C#). Sob essa condição, considere dois objetos, cada um de algum tipo de classe; um é denominado elemento e o outro é visitante .
O visitante declara um método Visite
, que toma o elemento como um argumento, para cada classe de elemento. visitantes concretos são derivados da classe de visitantes e implementam esses métodos Visite
, cada um dos quais implementa parte do algoritmo que opera na estrutura do objeto. O estado do algoritmo é mantido localmente pela classe de visitantes de concreto.
O elemento declara um método Aceite
para aceitar um visitante, tomando o visitante como um argumento. Elementos concretos , derivado da classe Element, implemente o método aceite
. Na sua forma mais simples, isso não passa de uma chamada para o método do visitante. Visite . Elementos compostos, que mantêm uma lista de objetos filhos, normalmente iteram sobre eles, chamando cada filho de Método de Acesso .
O cliente cria a estrutura do objeto, direta ou indiretamente, e instancia os visitantes concretos. Quando uma operação deve ser executada, que é implementada usando o padrão de visitante, ele chama o método Aceite
do (s) elemento (s) de nível superior.
Quando o método aceita
é chamado no programa, sua implementação é escolhida com base no tipo dinâmico do elemento e no tipo estático do visitante. Quando o método visite
associado é chamado, sua implementação é escolhida com base no tipo dinâmico do visitante e no tipo estático do elemento, como conhecido na implementação do aceitar Código> Método, que é o mesmo que o tipo dinâmico do elemento. (Como bônus, se o visitante puder lidar com um argumento do tipo de elemento especificado, o compilador capturará o erro.)
Assim, a implementação do método Visit
é escolhida com base no tipo dinâmico do elemento e no tipo dinâmico do visitante. Isso implementa efetivamente a despacho duplo. Para idiomas cujos sistemas de objetos suportam o despacho múltiplo, não apenas o despacho único, como LISP comum ou C# através do tempo de execução da linguagem dinâmica (DLR), a implementação do padrão do visitante é bastante simplificada (também conhecida Cubra todos os casos que estão sendo visitados. Um visitante dinâmico, desde que opere apenas dados públicos, esteja em conformidade com o princípio aberto/fechado (pois não modifica estruturas existentes) e com o princípio de responsabilidade única (uma vez que implementa o padrão do visitante em um componente separado).
Dessa maneira, um algoritmo pode ser escrito para atravessar um gráfico de elementos, e muitos tipos diferentes de operações podem ser realizados durante essa travessia, fornecendo diferentes tipos de visitantes para interagir com os elementos baseados nos tipos dinâmicos de ambos elementos e os visitantes.
C# Exemplo
Este exemplo declara uma classe ExpressionPrintingVisitor
separada que cuida da impressão. Se a introdução de um novo visitante de concreto for desejado, será criada uma nova classe para implementar a interface do visitante e novas implementações para os métodos de visita serão fornecidos. As classes existentes (literal e adição) permanecerão inalteradas.
usando Sistema;namespace Wikipédia;público interface Visitante( vazio Visita(Literal literal); vazio Visita(Adição adição);?público classe ExpressionPrintingVisitor : Visitante( público vazio Visita(Literal literal) ( Console.Linha de produção(literal.Valor); ? público vazio Visita(Adição adição) ( duplo esquerda Valor = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = adição.Esquerda.Obter valor(); duplo Certo. Valor = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = adição.Certo..Obter valor(); var soma = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = adição.Obter valor(); Console.Linha de produção("{0} + {1} = {2}", esquerda Valor, Certo. Valor, soma); ? ?público resumo classe Expressão( público resumo vazio Aceitar(Visitante v); público resumo duplo Obter valor();?público classe Literal : Expressão( público Literal(duplo valor) ( Isto é o seguinte..Valor = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = valor; ? público duplo Valor ( Vamos.; conjunto; ? público sobreposição vazio Aceitar(Visitante v) ( v.Visita(Isto é o seguinte.); ? público sobreposição duplo Obter valor() ( retorno Valor; ??público classe Adição : Expressão( público Adição(Expressão esquerda, Expressão Certo.) ( Esquerda = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = esquerda; Certo. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Certo.; ? público Expressão Esquerda ( Vamos.; conjunto; ? público Expressão Certo. ( Vamos.; conjunto; ? público sobreposição vazio Aceitar(Visitante v) ( Esquerda.Aceitar(v); Certo..Aceitar(v); v.Visita(Isto é o seguinte.); ? público sobreposição duplo Obter valor() ( retorno Esquerda.Obter valor() + Certo..Obter valor(); ??público estática classe Programa( público estática vazio Principal(string[] Args) ( // Emular 1 + 2 + 3 var e = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = novo novo Adição( novo novo Adição( novo novo Literal(1), novo novo Literal(2) ), novo novo Literal(3) ); var impressão Visitante = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = novo novo ExpressionPrintingVisitor(); e.Aceitar(impressão Visitante); Console.Leia mais Chaveiro(); ??
Exemplo de SmallTalk
Nesse caso, é de responsabilidade do objeto saber como imprimir em um fluxo. O visitante aqui é então o objeto, não o fluxo.
"Não há sintaxe para criar uma classe. As classes são criadas enviando mensagens para outras classes."Escrita subclasse: #ExpressionPrinter instância Variável Nomes: ' ' classeVariável Nomes: ' ' pacote: "Wikipedia" '.Linha de produção> Escreva: Um problema "Delega a ação ao objeto. O objeto não precisa ser de nenhum especial classe; ele só precisa ser capaz de entender a mensagem #putOn:" Um problema putOn: auto-eu próprio. ^ Um problema.Objeto subclasse: Expressão instância Variável Nomes: ' ' classeVariável Nomes: ' ' pacote: "Wikipedia" '.Expressão subclasse: Literal instância Variável Nomes: Valor ' classeVariável Nomes: ' ' pacote: "Wikipedia" '.Literal classe> com: um valor "método de fecho para construir uma instância da classe Literal" ^ auto-eu próprio novo novo valor: um valor; você mesmo..Literal>>valor: um valor "Melhor valor" valor ? um valor.Literal>putOn: Um passo "Um objeto literal sabe imprimir-se" Um passo PróximoPutAll: valor Como se chama?.Expressão subclasse: Adição instância Variável Nomes: Esquerda direita ' classeVariável Nomes: ' ' pacote: "Wikipedia" '.Adição classe>left: um Certo. b) "Método de fecho para construir uma instância da classe Addition" ^ auto-eu próprio novo novo esquerda: um; Certo. b); você mesmo..Adição> uma expressão "Melhor para a esquerda" esquerda ? uma expressão.AdiçãoDireita: uma expressão "Melhor para a direita" Certo. ? uma expressão.Adição>putOn: Um passo "Um objeto Addition sabe como imprimir-se" Um passo Próximo Ponha: $(. esquerda putOn: Um passo. Um passo Próximo Ponha: $+. Certo. putOn: Um passo. Um passo Próximo Ponha: $).Objeto subclasse: Programa instância Variável Nomes: ' ' classeVariável Nomes: ' ' pacote: "Wikipedia" '.Programa>principal | expressão fluxo | expressão ? Adição esquerda: (Adição esquerda: (Literal com: 1)
Certo. (Literal com: 2)
Certo. (Literal com: 3). fluxo ? Linha de produção em: (String novo: 100.). fluxo Escreva: expressão. Transcrição mostrar: fluxo conteúdo. Transcrição flush flush.
vá
Go não suporta a sobrecarga do método, portanto os métodos de visita precisam de nomes diferentes. Uma interface de visitante típica pode ser
tipo Visitante interface (visita Roda(roda Roda) stringvisita Engine(motor Motor) stringvisitarBody(corpo Corpo) stringvisitar o carro(carro Carro) string?
Java Exemplo
O exemplo a seguir está no idioma Java e mostra como o conteúdo de uma árvore de nós (neste caso descreve os componentes de um carro) pode ser impresso. Em vez de criar métodos Print
para cada subclasse de nós ( roda
, mecanismo
, corpo
e car < /code>), uma classe de visitante (
CarElementPrintVisitor
) executa a ação de impressão necessária. Como as subclasses de nó diferentes requerem ações ligeiramente diferentes para imprimir corretamente, carelementPrintVisitor
despacha as ações com base na classe do argumento passada para o método visite
. CarElementDovisitor
, que é análogo a uma operação de salvamento para um formato de arquivo diferente, é o mesmo.
Diagrama
Fontes
importação Java.util. Lista;interface Elemento do carro ( vazio aceitar(Veículo de Elevação visitante);?interface Veículo de Elevação ( vazio visita(Corpo corpo); vazio visita(Carro carro); vazio visita(Motor motor); vazio visita(Roda roda);?classe Roda implementos Elemento do carro ( privado final final String Nome; público Roda(final final String Nome) ( Isto é o seguinte..Nome = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Nome; ? público String Como chegar?() ( retorno Nome; ? @Override público vazio aceitar(Veículo de Elevação visitante) ( - Sim. * aceitar (CarElementVisitor) em implementos de roda * aceitar (CarElementVisitor) em CarElement, então a chamada * aceitar é limitado em tempo de execução. Isto pode ser considerado *o primeiro * despacho. No entanto, a decisão de chamada * visita (Wheel) (ao contrário da visita (Engine) etc.) pode ser * feito durante o tempo de compilação desde 'isso' é conhecido em compilação * Hora de ser uma Roda. Além disso, cada implementação de * CarElementVisitor implementa a visita (Wheel), que é * outra decisão tomada a tempo de execução. Isto pode ser * considerou o envio *segundo*. * visitante.visita(Isto é o seguinte.); ??classe Corpo implementos Elemento do carro ( @Override público vazio aceitar(Veículo de Elevação visitante) ( visitante.visita(Isto é o seguinte.); ??classe Motor implementos Elemento do carro ( @Override público vazio aceitar(Veículo de Elevação visitante) ( visitante.visita(Isto é o seguinte.); ??classe Carro implementos Elemento do carro ( privado final final Lista<Elemento do carro> elementos; público Carro() ( Isto é o seguinte..elementos = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Lista.de( novo novo Roda("à esquerda"), novo novo Roda("front right"), novo novo Roda("para a esquerda"), novo novo Roda("à direita"), novo novo Corpo( novo novo Motor() ); ? @Override público vazio aceitar(Veículo de Elevação visitante) ( para (Elemento do carro elemento : elementos) ( elemento.aceitar(visitante); ? visitante.visita(Isto é o seguinte.); ??classe Elemento de carro implementos Veículo de Elevação ( @Override público vazio visita(Corpo corpo) ( Sistema.fora.Impressão("Mover o meu corpo"); ? @Override público vazio visita(Carro carro) ( Sistema.fora.Impressão("Começar o meu carro"); ? @Override público vazio visita(Roda roda) ( Sistema.fora.Impressão("Kicking my" + roda.Como chegar?() + "Roda"); ? @Override público vazio visita(Motor motor) ( Sistema.fora.Impressão("Iniciar o meu motor"); ??classe Máquina de montagem automática implementos Veículo de Elevação ( @Override público vazio visita(Corpo corpo) ( Sistema.fora.Impressão("Corpo vivo"); ? @Override público vazio visita(Carro carro) ( Sistema.fora.Impressão("Visiting car"); ? @Override público vazio visita(Motor motor) ( Sistema.fora.Impressão("O motor de fuga"); ? @Override público vazio visita(Roda roda) ( Sistema.fora.Impressão("Visiting" + roda.Como chegar?() + "Roda"); ??público classe VisitanteDemo ( público estática vazio principal(final final String[] Args) ( Carro carro = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = novo novo Carro(); carro.aceitar(novo novo Máquina de montagem automática()); carro.aceitar(novo novo Elemento de carro()); ??
saída
Visitando a roda esquerda frontal Visitando roda direita frontal Visitando a roda esquerda Visitando a roda direita Corpo de visita Motor de visita Carro de visita Chutando minha roda esquerda Chutando minha roda direita frontal Chutando minha roda esquerda de trás Chutando minha roda traseira direita Movendo meu corpo A partir do meu motor A partir do meu carro
Exemplo de Lisp comum
Fontes
(Defclass auto auto () (elementos : : elementos)(Defclass auto-parte () (Nome : : Nome : Formulário inicial "" )(O que foi? print-object (p auto-parte) fluxo) (print-object (valor de fenda p Nome) fluxo)(Defclass roda (auto-parte) ()(Defclass corpo (auto-parte) ()(Defclass motor (auto-parte) ()(Defensivo Travesseiro (função objeto outros objetos)(O que foi? Travesseiro (função (um auto auto) outros objetos) (com lotes (elementos) um (lista de tarefas (e elementos) (- Sim. função e outros objetos));; captura de todos(O que foi? fazer alguma coisa (objeto outros objetos) (formato ) "Não sei como ~s e ~s devem interagir ~%" objeto outros objetos);; visitação envolvendo roda e inteiro(O que foi? fazer alguma coisa (objeto roda) (outros objetos Intérprete) (formato ) "Roda mordaz ~s vezes ~%" objeto outros objetos);; visitação envolvendo roda e símbolo(O que foi? fazer alguma coisa (objeto roda) (outros objetos símbolo) (formato ) "Roda mordente ~s simbolicamente usando símbolo ~s~%" objeto outros objetos)(O que foi? fazer alguma coisa (objeto motor) (outros objetos Intérprete) (formato ) "começando motor ~s vezes ~%" objeto outros objetos)(O que foi? fazer alguma coisa (objeto motor) (outros objetos símbolo) (formato ) "começando motor ~s simbolicamente usando símbolo ~s~%" objeto outros objetos)(Deixa-me. (um (make-instance "Auto" : elementos "(,(make-instance Roda : Nome "front-left-wheel") ,(make-instance Roda : Nome "Roda da frente direita") ,(make-instance Roda : Nome "rear-left-wheel") ,(make-instance Roda : Nome "rear-right-wheel") ,(make-instance "O corpo" : Nome "corpo") ,(make-instance Motor : Nome "engine"))) ;; atravessar elementos de impressão ;; stream *standard-output* desempenha o papel de outro objeto aqui (Travesseiro # 'impressão um * saída padrão*) (Terceirizado) ; imprimir nova linha ;; transversal com contexto arbitrário de outro objeto (Travesseiro # 'fazer alguma coisa um 42) ;; transversal com contexto arbitrário de outro objeto (Travesseiro # 'fazer alguma coisa um "abc")
saída
"front-left-wheel" "Roda da frente direita" "rear-left-wheel" "rear-right-wheel" "corpo" "engine" roda chutando "front-left-wheel" 42 vezes roda chutando "front-right-wheel" 42 vezes roda chutando "rear-left-wheel" 42 vezes roda chutando "rear-right-wheel" 42 vezes não sei como "corpo" e 42 devem interagir motor de partida "engine" 42 vezes roda chutando "front-left-wheel" simbolicamente usando símbolo ABC roda chutando "front-right-wheel" simbolicamente usando símbolo ABC roda chutando "rear-left-wheel" simbolicamente usando símbolo ABC roda chutando "rear-right-wheel" simbolicamente usando símbolo ABC não sei como "corpo" e ABC devem interagir motor de partida "engine" simbolicamente usando símbolo ABC
Notas
O parâmetro Other-Object
é supérfluo no Traverse
. O motivo é que é possível usar uma função anônima que chama o método de destino desejado com um objeto capturado lexicamente:
(O que foi? Travesseiro (função (um auto auto) ;; outro objeto removido (com lotes (elementos) um (lista de tarefas (e elementos) (- Sim. função e)) ; de aqui também ; ;; maneira alternativa de imprimir-traverso (Travesseiro (Lambda (o) (impressão o * saída padrão*) um) ;; forma alternativa de fazer alguma coisa com ; elementos de um e inteiro 42 (Travesseiro (Lambda (o) (fazer alguma coisa o 42) um)
Agora, o despacho múltiplo ocorre na chamada emitida do corpo da função anônima e, portanto, Traverse
é apenas uma função de mapeamento que distribui um aplicativo de função sobre os elementos de um objeto. Assim, todos os traços do padrão do visitante desaparecem, exceto a função de mapeamento, na qual não há evidências de que dois objetos estejam envolvidos. Todo o conhecimento de haver dois objetos e um despacho em seus tipos está na função Lambda.
Exemplo de Python
O Python não suporta a sobrecarga do método no sentido clássico (comportamento polimórfico de acordo com o tipo de parâmetros passados); portanto, o " visite " Os métodos para os diferentes tipos de modelos precisam ter nomes diferentes.
Fontes
"Exemplo de padrão de visitantes."a partir de Abdc importação ABCMeta, abstratoNOT_IMPLEMENTO = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = "Deves implementar isto."classe Elemento do carro(metaclasse= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =ABCMeta: O que foi? de aceitar(auto-eu próprio, visitante: aumento Não implementado Erro(NOT_IMPLEMENTO)classe Corpo(Elemento do carro: de aceitar(auto-eu próprio, visitante: visitante.visitarBody(auto-eu próprio)classe Motor(Elemento do carro: de aceitar(auto-eu próprio, visitante: visitante.visita Engine(auto-eu próprio)classe Roda(Elemento do carro: de Não.(auto-eu próprio, Nome: auto-eu próprio.Nome = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Nome de aceitar(auto-eu próprio, visitante: visitante.visita Roda(auto-eu próprio)classe Carro(Elemento do carro: de Não.(auto-eu próprio: auto-eu próprio.elementos = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Não. Roda("à esquerda"), Roda("front right"), Roda("para a esquerda"), Roda("à direita"), Corpo( Motor() ] de aceitar(auto-eu próprio, visitante: para elemento em auto-eu próprio.elementos: elemento.aceitar(visitante) visitante.visitar o carro(auto-eu próprio)classe Veículo de Elevação(metaclasse= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =ABCMeta: O que foi? de visitarBody(auto-eu próprio, elemento: aumento Não implementado Erro(NOT_IMPLEMENTO) O que foi? de visita Engine(auto-eu próprio, elemento: aumento Não implementado Erro(NOT_IMPLEMENTO) O que foi? de visita Roda(auto-eu próprio, elemento: aumento Não implementado Erro(NOT_IMPLEMENTO) O que foi? de visitar o carro(auto-eu próprio, elemento: aumento Não implementado Erro(NOT_IMPLEMENTO)classe Elemento de carro(Veículo de Elevação: de visitarBody(auto-eu próprio, corpo: impressão("Mover o meu corpo.") de visitar o carro(auto-eu próprio, carro: impressão("Começar o meu carro.") de visita Roda(auto-eu próprio, roda: impressão("A matar-me Não. roda.".formato(roda.Nome) de visita Engine(auto-eu próprio, motor: impressão("Começar o meu motor.")classe Máquina de montagem automática(Veículo de Elevação: de visitarBody(auto-eu próprio, corpo: impressão("Corpo vivo.") de visitar o carro(auto-eu próprio, carro: impressão("Visiting car.") de visita Roda(auto-eu próprio, roda: impressão("Visiting Não. roda.".formato(roda.Nome) de visita Engine(auto-eu próprio, motor: impressão("O motor de fuga".)carro = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Carro()carro.aceitar(Máquina de montagem automática()carro.aceitar(Elemento de carro()
saída
Visitando a roda esquerda.A visitar a roda direita.A voltar à roda esquerda.A voltar à roda direita.Corpo de visita.Motor de visita.A visitar o carro.A dar pontapés na minha roda esquerda.A dar pontapés na roda direita.A dar pontapés na roda esquerda.A dar pontapés na roda direita.A mover o meu corpo.A começar o meu motor.A começar o meu carro.
Abstração
Usando o Python 3 ou acima, permite fazer uma implementação geral do método de aceitação:
classe Acessível: de aceitar(auto-eu próprio, visitante: Olhar = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = "visit_" + tipo(auto-eu próprio).O que é isto?.substituir("., "_") retorno O que é?(visitante, Olhar)auto-eu próprio)
Pode-se estender isso para iterar sobre a ordem de resolução do método da classe 39, se eles gostarem de recorrer às classes já implementadas. Eles também poderiam usar o recurso de gancho de subclasse para definir a pesquisa com antecedência.
Padrões de design relacionados
- Padrão do iterador – define um princípio transversal como o padrão do visitante, sem fazer uma diferenciação do tipo dentro dos objetos atravessados
- Codificação da Igreja – um conceito relacionado da programação funcional, em que os tipos de união/sum marcados podem ser modelados usando os comportamentos de "visitantes" em tais tipos, e que permite que o padrão do visitante emular variantes e padrões.