Saltar al contenido

Iterator

Un patrón de comportamiento para recorrer una colección sin que el código que la recorre conozca su estructura interna.

6 min. de lectura

Iterator es un patrón de comportamiento que permite recorrer los elementos de una colección sin exponer su representación interna.

El problema

El catálogo de AndesShop empieza guardando los productos en una simple List. Con el tiempo, para acelerar las búsquedas por categoría, se reorganiza internamente en un árbol de categorías; y para el catálogo destacado de temporada, se mantiene además una estructura ordenada por popularidad. Si el código que recorre el catálogo depende de que sea siempre una List (usando índices, por ejemplo), cada cambio en la estructura interna rompe todo el código que la recorre.

La solución

Iterator extrae la lógica de recorrido a un objeto separado, que expone una interfaz simple y uniforme (hasNext() / next()) sin importar cómo esté organizada la colección por dentro. El código cliente recorre a través del iterador y nunca accede directamente a la estructura interna — así, esa estructura puede cambiar sin que el código que la recorre se entere.

Estructura de Iterator: el aggregate sabe crear su iterador, y el cliente recorre sin conocer la estructura interna de la colección.

Ejemplo en Java

// Java ya define esta interfaz en java.util.Iterator — acá se muestra el mecanismo
interface ProductIterator {
    boolean hasNext();
    Product next();
}

// El recorrido conoce la estructura interna (un árbol), el cliente no.
// Recorre nivel por nivel (breadth-first): por eso usa colas (Queue) de punta a
// punta, en vez de una pila — mezclar semántica de pila (push/pop) con un
// agregado masivo como addAll suele terminar en un orden de recorrido distinto
// al que el nombre de las variables sugiere.
class CatalogTreeIterator implements ProductIterator {
    private final Queue<Category> pendingCategories = new LinkedList<>();
    private final Queue<Product> buffer = new LinkedList<>();

    public CatalogTreeIterator(Category root) {
        pendingCategories.offer(root);
        advance();
    }

    private void advance() {
        while (buffer.isEmpty() && !pendingCategories.isEmpty()) {
            Category current = pendingCategories.poll();
            buffer.addAll(current.getDirectProducts());
            pendingCategories.addAll(current.getSubcategories());
        }
    }

    public boolean hasNext() {
        return !buffer.isEmpty();
    }

    public Product next() {
        Product product = buffer.poll();
        advance();
        return product;
    }
}
// Client code: recorre sin saber que por dentro hay un árbol
ProductIterator iterator = new CatalogTreeIterator(trekkingCategory);
while (iterator.hasNext()) {
    Product product = iterator.next();
    System.out.println(product.getName());
}

Cuándo usarlo

  • Cuando tu colección tiene una estructura interna compleja (árboles, grafos, colecciones combinadas) y querés ocultarla del código que solo necesita recorrerla.
  • Cuando necesitás varias formas distintas de recorrer la misma colección (por categoría, por popularidad, por precio) sin ensuciar la clase de la colección con cada una de ellas.

Cuándo evitarlo

Una colección simple (una lista plana, por ejemplo) que ya se recorre bien con las herramientas estándar del lenguaje no necesita un iterador propio.

Ventajas y desventajas

VentajasDesventajas
Simplifica la clase de la colección, que delega el recorrido a otro objetoPuede ser excesivo para colecciones simples que ya se recorren bien con las herramientas del lenguaje
Permite tener varios recorridos distintos sobre la misma colección al mismo tiempoCada nuevo tipo de recorrido implica una clase de iterador nueva
Unifica cómo se recorren estructuras internas muy distintas entre sí

Relación con otros patrones

  • Se usa junto con Composite para recorrer estructuras de árbol sin exponer sus niveles internos.
  • Memento a veces se combina con Iterator para poder capturar y restaurar el punto exacto de un recorrido.

Te sirvió, compartilo

// ¿te sirvió?
// compartilo