strategy patterns pattern patrones patron objetivo gof explicacion estrategia diseño design-patterns visitor

design patterns - patterns - ¿Por qué usar el patrón de visitante?



visitor design pattern (5)

Otra buena ventaja de los visitantes, es que son fáciles de extender, y si su idioma lo permite, incluso puede usar lamdbas para limpiar cosas.

Duplicado de: ¿Cuándo debería usar el patrón de diseño de visitante?

¿Por qué alguien querría usar el patrón de visitante? He leído un par de artículos, pero no obtengo nada.

Si necesito una función para facturar una personalizada, podría usar

Custom.Accept(BillVisitor)

o algo así como

Bill(Customer)

El segundo es menos complejo y la función de Bill aún está separada de la clase Cliente. Entonces, ¿por qué querría usar el patrón de visitante?


En mi aplicación CAD / CAM tengo Paths and Collections of Paths (PathList). A veces tengo que generar una colección de formas. No solo tengo que generar esta colección particular de formas, debo incluirla con otra colección de formas. A menudo necesito una docena o más de parámetros para transmitir toda la información necesaria para hacer los cálculos.

Todos los cálculos de formas (simples o complejos) en mi CAM se canalizan a una Lista de rutas que se envía a las diferentes máquinas.

Con este diseño, sería mejor tener alguna configuración que implique agregar el resultado a una sola colección.

El visitante de ruta se adapta muy bien. Cada cálculo de forma se encapsula en su propia clase con las propiedades tan complejas como sea necesario.

Entonces Kitchen Visitor puede tener 8 formas para Pathlist

Mientras que Kitchen Counter Visitor agrega 6 formas.

El cajón Visitor agrega algunos más.

Luego reparto el PathList resultante al resto del sistema como cualquier otro generador de formas.

Fácilmente tengo opciones agregando otro visitante o no ejecutando algunos. Para un chico que solo quiere un mostrador y cajones, solo necesito correr dos visitas.

El código resultante es muy legible, lo cual es importante cuando vuelvo a visitar esta área 3, 5 o 10 años más adelante. Además, debido a los cambios de encapsulamiento en un visitante, tiene un impacto mínimo o nulo en otros visitantes.

Además, ahora tengo un patrón de diseño estandarizado para agregar cualquier funcionalidad nueva a PathList implementando el patrón de visitante.

Por ejemplo, solía ser que nuestro editor de propiedades solo funcionaba en una sola ruta. Cuando cambiamos a la edición de varias rutas, fue fácil implementar visitas personalizadas para realizar cambios globales en todas las rutas. Era más legible que usar bucles dentro de los delegados.

Pero en última instancia todo se reduce a juicio y preferencia.


El problema surge cuando tienes una estructura compleja, es decir, una jerarquía u otra cosa que no es simplemente lineal. Cuando no se puede simplemente iterar sobre la estructura, un visitante es muy útil.

Si tengo una jerarquía (o árbol), cada nodo tiene una lista de elementos secundarios. Cuando quiero aplicar un proceso a cada nodo en el árbol, es agradable crear un Visitante.

Un nodo puede aplicar el visitante a sí mismo y a cada uno de sus Nodos secundarios. Cada niño, de manera transitiva, hace lo mismo (aplica el Visitante a sí mismo y luego a cualquier niño).

Este uso de un visitante funciona muy bien.

Cuando tienes una estructura de datos súper simple, Visitor no agrega mucho valor.


En ambos casos, el visitante está separado de la clase de los clientes. La ventaja sería si también quisieras abstraer al visitante de la clase de la persona que llama. En el segundo caso, la clase llamante debe saber acerca de la facturación. En su lugar, podría tener otra rutina en algún lugar que devuelva un IVisitor. El código de llamada podría llamar a Custom.Accept (IVisitor) y no saber nada sobre lo que está haciendo el visitante.

Básicamente, en este caso y en el caso mencionado por S.Lott, puede pensar en el visitante como un delegado. Es una función que puede pasar como un objeto y usar donde sea necesario.


El patrón de visitante es un truco para los lenguajes que no admiten el despacho múltiple directamente (el lenguaje como C ++ y Java solo admiten el despacho único basado en el objeto. CLOS admite el despacho múltiple). En este caso, si desea que tanto Bill como Customer sean polimórficos, deberá usar dos interfaces, BillVisitor y Customer en idiomas de despacho únicos. Por ejemplo: la implementación de accept es típicamente:

void accept(BillVisitor visitor) { visitor.bill(this); } // java syntax

Tenga en cuenta que tanto las facturas de Customer # accept como de BillVisitor # pueden ser anuladas por sus respectivas subclases, lo que resulta en una combinación muy rica de comportamiento en tiempo de ejecución que de otro modo no se puede lograr. En realidad, es un superconjunto de lo que la mayoría de la gente describe aquí como un sustituto del cierre para aplicar la funcionalidad a estructuras de datos complejas.