💡 Ver Caso Práctico: Ejemplo Práctico del Patrón Visitor
Visitor (Visitante) es un patrón de diseño comportamental que permite separar algoritmos de los objetos sobre los que operan, añadiendo nuevos comportamientos a una jerarquía de clases existente sin modificarlas.
Propósito y Caso de Uso
Utiliza Visitor cuando tengas una jerarquía de clases estable (ej. distintos tipos de nodos de un árbol de contenido: TextNode, ImageNode, CodeNode) y necesites aplicarle operaciones muy variadas y cambiantes (exportar a HTML, contar palabras, calcular tiempo de lectura) sin ensuciar cada clase con un método por operación. Combina bien con Composite para recorrer estructuras jerárquicas.
Estructura del Patrón
- Visitante (Interfaz): Declara un método
visit()por cada tipo concreto de elemento. - Visitantes Concretos: Implementan una operación completa (ej. exportar a HTML) para todos los tipos de elemento.
- Elementos: Implementan un método
accept(visitor)que invoca al método correspondiente del visitante (Double Dispatch).
Flujo de Funcionamiento
- Invocación: El cliente recorre los elementos y llama a
element.accept(visitor)en cada uno. - Double dispatch: El elemento invoca de vuelta al método específico del visitante para su propio tipo (
visitor.visitText(this)). - Ejecución de la operación: El visitante ejecuta la lógica correspondiente, sin que el elemento conozca los detalles.
Ejemplos de Implementación Reales
interface Visitor {
visitText(node: TextNode): void;
visitImage(node: ImageNode): void;
}
interface ContentNode { accept(visitor: Visitor): void; }
class TextNode implements ContentNode {
constructor(public text: string) {}
accept(visitor: Visitor) { visitor.visitText(this); }
}
class ImageNode implements ContentNode {
constructor(public alt: string) {}
accept(visitor: Visitor) { visitor.visitImage(this); }
}
class WordCountVisitor implements Visitor {
total = 0;
visitText(node: TextNode) { this.total += node.text.split(' ').length; }
visitImage() { /* las imágenes no aportan palabras */ }
}
const nodes: ContentNode[] = [new TextNode('Hola mundo'), new ImageNode('diagrama')];
const counter = new WordCountVisitor();
nodes.forEach((n) => n.accept(counter));
console.log(counter.total); // 2Cuándo NO usarlo
Si la jerarquía de clases cambia con frecuencia (añadir tipos nuevos obliga a modificar TODOS los visitantes), o solo hay una operación estable, un método normal en cada clase es más simple (YAGNIGlosarioYAGNI (You Aren't Gonna Need It)Principio de Extreme Programming (XP) que establece que un programador no debe añadir funcionalidad hasta que sea estrictamente necesario. Su objetivo es evitar la sobre-ingeniería (over-engineering), previniendo código para funcionalidades hipotéticas.Ver término completo →).