Visitor pattern: ¡descubre qué es!

La Programación Orientada a Objetos (OOP), que se clasifica como una subcategoría del paradigma de programación imperativa, ha ganado mucha importancia en los últimos años. Este sistema, en el que todos los bloques de un proyecto de software se describen como objetos cuyo comportamiento es determinado por las clases correspondientes, posee algunas ventajas decisivas sobre otros estilos de programación. Uno de los argumentos a su favor es que permite reutilizar fácilmente las partes del programa ya diseñadas.

Para que esta reutilización, así como la implementación, adaptabilidad y comprobabilidad de los objetos incorporados sea aún más sencilla, el grupo de desarrolladores software “Gang of four” presentó sus patrones de diseño en el libro Patrones de Diseño: elementos del software reutilizable orientado a objetos. Uno de los más de 20 patrones de diseño diferentes descritos en el libro es el llamado visitor pattern, que describimos en detalle en este artículo.

¿En qué consiste el visitor pattern?

El visitor pattern es un patrón de solución para separar un algoritmo de la estructura del objeto en el que se ejecuta. Describe una forma de añadir nuevas operaciones a las estructuras de los objetos existentes sin modificar dichas estructuras. Gracias a esta propiedad, el visitor pattern es una manera de implementar el Principio Abierto-Cerrado (OCP). Este principio de desarrollo de software, orientado a objetos, se basa en el hecho de que todas las unidades de software, como los módulos, clases o métodos, están simultáneamente abiertas para extensiones y cerradas para modificaciones.

Nota

En castellano, el visitor pattern se llama también patrón visitor.

El visitor pattern es uno de los 23 patrones de diseño, en la categoría de los patrones de comportamiento, descritos y publicados en 1994 por los informáticos Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. Dado que los cuatro son también conocidos en la escena de los desarrolladores como Gang of Four o GoF para abreviar, a estos patrones también se los llama diseños de patrón GoF.

¿Para qué sirve el visitor design pattern?

Puesto que la estructura de los objetos está compuesta de muchas clases inconexas y requiere cada vez más operaciones, para los desarrolladores es muy inconveniente implementar una nueva subclase para cada nueva operación. El resultado es un sistema plagado con varias clases de nodos diferentes que no solo es difícil de entender, sino también de mantener y modificar. La instancia esencial del visitor pattern es el Visitor, que permite añadir nuevas funciones virtuales a una familia de clases sin modificarlas.

Nota

Las funciones o métodos virtuales definen las funciones que se deben ejecutar, cuyo objetivo no tiene que ser conocido en el momento de la compilación. Estas funciones representan una importante herramienta de los lenguajes orientados a los objetos.

El visitor pattern establece que el objeto Visitor se define por separado y tiene el fin de implementar una operación que se realiza en uno o más elementos de la estructura del objeto. Los clientes que acceden a la estructura del objeto llaman entonces a la operación de envió accept(visitor) en el elemento en cuestión, lo que delega la petición en el objeto visitante aceptado. Así, el objeto Visitor puede realizar la operación necesaria.

Representación gráfica del visitor pattern (diagrama UML)

La interacción entre los elementos existentes y los objetos Visitor, integrados según el visitor pattern, se puede ilustrar mejor mediante una representación gráfica de las relaciones y procesos de un software de ejemplo orientado a objetos. El método de representación más apropiado para esto es el UML (Unified Modeling Language), que, por este motivo, se ha utilizado también en el siguiente diagrama de clases para el visitor pattern.

Ventajas e inconvenientes del visitor pattern

El visitor pattern es una forma ya de por sí sofisticada y elaborada de ampliar las unidades existentes de un software orientado a objetos. Si hay que añadir una nueva operación, se puede hacer con facilidad añadiendo un nuevo Visitor. Además, esta estrategia también permite centralizar cualquier código funcional: la ejecución respectiva de una operación está centralizada en la clase Visitor y no es necesario añadirla a las otras clases. La ventaja más importante del software basado en el visitor pattern es, en resumen, que el código fuente subyacente de los objetos utilizados no necesita pasar por modificaciones constantes. En su lugar, la lógica se transfiere a los Visitors y a las clases Visitor que actúan como sustitutos.

Naturalmente, sin embargo, el visitor pattern no es la solución ideal en todos los casos. Si trabajas según los principios de este patrón, debes ser consciente de lo siguiente: los cambios más pequeños en la clase de un elemento suelen requerir adaptaciones de las clases Visitor. Además, se requiere un trabajo adicional para introducir posteriormente nuevos elementos, ya que también requieren la aplicación de métodos de visit(), que deben añadirse también a las clases ConcreteVisitor. Por lo tanto, la excelente capacidad de ampliación de las unidades de software se paga con un cierto grado de esfuerzo.

¿Para qué se utiliza el visitor pattern?

El visitor pattern puede simplificar considerablemente las tareas recurrentes en el desarrollo de software. Este patrón de diseño es apto sobre todo para los desarrolladores que siguen el paradigma de la programación orientada a objetos. Desde su introducción en 1994, el patrón se ha vuelto ubicuo en la escena de la programación. En principio, el tipo de proyecto de software no es lo importante a la hora de decidir la utilidad del patrón. Tampoco hay restricciones concretas con respecto a los lenguajes de programación utilizados, siempre y cuando se recuerde que funciona mejor en los paradigmas orientados a objetos.

Entre los lenguajes populares en los que el visitor pattern tiene un papel esencial, están los siguientes:

  • C++
  • C#
  • Java
  • PHP
  • Python
  • JavaScript
  • Golang
Para mostrar este video, se requieren cookies de terceros. Puede acceder y cambiar sus ajustes de cookies aquí.

Ejemplo práctico para el uso del visitor pattern

La utilidad y el propósito del visitor pattern no son tan sencillos de entender. Sin embargo, cualquiera que aprenda a programar hoy en día seguramente entrará en contacto con este patrón y su implementación.

Para entender el visitor pattern, a menudo se utiliza la analogía de un trayecto en taxi. Un cliente pide un taxi, que llegará a su puerta. Una vez que la persona se sienta en el taxi, de visita, el taxi (o el conductor) tiene el control total del transporte de la persona.

Las compras en un supermercado también se utilizan a menudo como ejemplo de un visitor pattern. El comprador recoge los bienes deseados en el carrito de la compra, que representa visualmente el conjunto de elementos de la estructura del objeto. Cuando llega a la caja, el cajero actúa como un visitante que escanea los precios y el peso de los distintos artículos (o elementos) de la compra para calcular los costes totales incurridos.

Ejemplo de código según el visitor pattern (PHP)

Finalmente, el siguiente código ilustra una implementación simple y básica del visitor pattern en PHP.

        return 'B';
	}
	public function getData() {
		return $this->the_data;
	}
	recibir public function (Visitante $visitante) {
		$visitante->VisitaDeElementB($this);
	}
}
abstract class Visitante {
	abstract function VisitaDeElementA(ElementA $elem);
	abstract function VisitaDeElementB(ElementB $elem);
}
class Visitante1 extends Visitante {
	private $characteristics;
	public function getCharacs() {
		return $this->characteristics;
	}
	public function VisitaDeElementA(ElementA $elem) {
		$this->characteristics = 'Info:'.$elem->getInfo();
	}
	public function VisitaDeElementB(ElementB $elem) {
		$this->characteristics = 'DATA:'.$elem->getData().'!!';
	}
}
function Test() {
	write_line('Inicio del test');
	// Estructura del objeto
	$elemente = array (
		new ElementA('Hola', 'Nuevo!!'),
		new ElementB('Por fin')
	);
	$bes1 = new Visitante1();
	foreach ($elemente as $element) {
		$element->aceptar($bes1);
		write_line('Tras visitar Element '.$element->getName().': '.$bes1-			>getCharacs());
}
}
function write_line($text) {
	print $text.'<br>';
}
Test();

La salida de este fragmento de código de ejemplo tiene la siguiente forma:

Inicio del test
Después de visitar Element A: Información: [Hola, Nuevo!!]
Después de visitar Element B: DATA:(Por fin.)!!