🔄 El Patrón Iterator: El Mando a Distancia Universal
El Patrón Iterator (Iterador) es probablemente el patrón de diseño que más usas sin darte cuenta (foreach, ¿te suena?). Su objetivo es permitir recorrer los elementos de una colección sin exponer lo que está por debajo (lista, pila, árbol, etc.).
El problema que resuelve es este:
¿Cómo puedes acceder a los elementos de una colección compleja de forma secuencial sin tener que conocer y acoplarte a su estructura interna?
La respuesta es extraer la lógica de recorrido a un objeto separado llamado Iterador.

📺 1. Un ejemplo sencillo: El mando de la tele
Imagina que tienes una televisión (la colección):
- La tele tiene canales guardados en su memoria interna (podría ser una lista, un array, o lo que sea).
- Tú usas el mando a distancia (el iterador).
- Pulsas “Siguiente” (
next()) o “Anterior”. No necesitas saber cómo la tele sintoniza la frecuencia o dónde guarda el número del canal. Solo sabes que si das a “Siguiente”, ves el siguiente canal.
Concepto (Analogía) | Rol en Iterator | Tarea Principal |
|---|---|---|
Televisión | Agregado (Colección) | Contiene los datos reales y crea el iterador. |
Mando a Distancia | Iterador | Lleva la cuenta de la posición actual y sabe cómo avanzar. |
🛠️ 2. Los tres pilares del patrón Iterator
1. Interfaz iterador
- Define las operaciones para recorrer la colección:
next(),hasMore(),current().
2. Iterador concreto
- Implementa la interfaz y mantiene la posición actual en el recorrido.
3. Interfaz agregado (colección)
- Define un método para crear un iterador compatible con la colección.
🤔 1. ¿Qué ventaja tiene separar la lógica de iteración de la propia colección?
🎵 3. El ejemplo clásico: Playlist de Spotify
Tienes una lista de canciones. Puedes querer recorrerla:
- En orden normal (1, 2, 3…).
- En modo aleatorio (Shuffle).
- Por artista.
En lugar de llenar la clase Playlist con métodos getSiguienteRandom(), getSiguientePorArtista(), creas distintos iteradores (IteradorAleatorio, IteradorSecuencial).
🤔 2. En PHP, ¿qué interfaz nativa facilita la implementación de este patrón?
✅ 4. ¿Por Qué Usarlo?
- Principio de Responsabilidad Única: Limpias tus clases de colección de algoritmos de recorrido complejos.
- Intercambiabilidad: Puedes cambiar la forma de recorrer los datos sin cambiar el código que los usa.
- Uniformidad: Usas la misma interfaz para recorrer arrays, árboles, listas enlazadas, etc.
❌ 5. Desventaja a Considerar
- Sobreingeniería: Si solo vas a recorrer un array simple, usar un iterador completo es matar moscas a cañonazos. Un simple
foreachoforbasta.
🤔 3. ¿Puede un iterador modificar la colección mientras la recorre?
💡 6. Conclusión
El Iterator es fundamental para escribir algoritmos genéricos que funcionen con cualquier tipo de colección. Te da la libertad de cambiar cómo guardas los datos sin romper el código que los lee.
🧠 7. Ejemplo Práctico en PHP
Vamos a crear un iterador personalizado para una colección de palabras.
<?php
// 🔹 1. Interfaz Iterador (Simplificada)
interface IteradorPersonalizado
{
public function tieneSiguiente(): bool;
public function siguiente();
}
// 🔹 2. Colección Concreta
class ColeccionPalabras
{
private array $items = [];
public function agregar(string $item): void
{
$this->items[] = $item;
}
public function getItems(): array
{
return $this->items;
}
public function getIterador(): IteradorPersonalizado
{
return new IteradorOrdenAlfabetico($this);
}
}
// 🔹 3. Iterador Concreto
class IteradorOrdenAlfabetico implements IteradorPersonalizado
{
private ColeccionPalabras $coleccion;
private int $posicion = 0;
private array $cacheOrdenada;
public function __construct(ColeccionPalabras $coleccion)
{
$this->coleccion = $coleccion;
// Copiamos y ordenamos los datos para iterar alfabéticamente
$this->cacheOrdenada = $coleccion->getItems();
sort($this->cacheOrdenada);
}
public function tieneSiguiente(): bool
{
return isset($this->cacheOrdenada[$this->posicion]);
}
public function siguiente()
{
$item = $this->cacheOrdenada[$this->posicion];
$this->posicion++;
return $item;
}
}
// 🔹 4. Uso
$coleccion = new ColeccionPalabras();
$coleccion->agregar("Zanahoria");
$coleccion->agregar("Arroz");
$coleccion->agregar("Manzana");
$iterador = $coleccion->getIterador();
echo "--- Lista de la compra ordenada ---\n";
while ($iterador->tieneSiguiente()) {
echo "• " . $iterador->siguiente() . "\n";
}
// 🖥️ Salida:
// --- Lista de la compra ordenada ---
// • Arroz
// • Manzana
// • Zanahoria
EA, ¡saluditos y nos vemos en los bares! 🍻