Menu
Coddy logo textTech

Patrón Iterator

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 76 de 87.

El Patrón Iterator es un patrón de diseño de comportamiento que proporciona una forma de acceder a los elementos de una colección de manera secuencial sin exponer su estructura subyacente. Ya sea que estés trabajando con un arreglo, una lista enlazada o un árbol, el iterador te brinda una forma uniforme de recorrer los elementos.

El patrón separa la lógica de recorrido de la propia colección. Involucra dos componentes principales: una interfaz Iterator que define métodos para recorrer elementos, y un Iterable (o Agregado) que crea iteradores para su colección:

interface Iterator<T> {
    boolean hasNext();
    T next();
}

interface Container<T> {
    Iterator<T> createIterator();
}

class BookShelf implements Container<String> {
    private String[] books;
    private int count = 0;
    
    public BookShelf(int size) {
        books = new String[size];
    }
    
    public void addBook(String book) {
        books[count++] = book;
    }
    
    public Iterator<String> createIterator() {
        return new BookIterator();
    }
    
    private class BookIterator implements Iterator<String> {
        private int index = 0;
        
        public boolean hasNext() {
            return index < count;
        }
        
        public String next() {
            return books[index++];
        }
    }
}

El iterador mantiene su propio estado de recorrido, permitiendo que múltiples iteradores recorran la misma colección de forma independiente. Los clientes utilizan el iterador sin saber cómo la colección almacena sus datos:

BookShelf shelf = new BookShelf(3);
shelf.addBook("Design Patterns");
shelf.addBook("Clean Code");

Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

Las interfaces integradas Iterable e Iterator de Java siguen exactamente este patrón, razón por la cual puedes usar bucles for mejorados con cualquier clase que implemente Iterable. El Patrón Iterator es esencial cuando necesitas proporcionar múltiples métodos de recorrido o para ocultar estructuras internas complejas del código cliente.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de lista de reproducción utilizando el Patrón Iterator! Crearás una lista de reproducción de música que almacena canciones y proporciona un iterador personalizado para recorrerlas secuencialmente, sin exponer cómo se almacenan las canciones internamente. Este es un caso de uso perfecto para el Patrón Iterator, permitiendo a los usuarios navegar por tu colección a través de una interfaz limpia y uniforme.

Organizarás tu código en cuatro archivos:

  • Iterator.java: Define tu interfaz genérica Iterator<T> con dos métodos: hasNext() que devuelve un booleano indicando si existen más elementos, y next() que devuelve el siguiente elemento de tipo T.
  • Playlist.java: Crea la clase agregada que contiene tus canciones. Tu Playlist debe almacenar canciones en un arreglo de String con una capacidad fija (pasada al constructor) y rastrear cuántas canciones se han añadido. Incluye un método addSong(String song) para añadir canciones a la lista de reproducción.

    Tu Playlist necesita un método createIterator() que devuelva un Iterator<String>. Implementa esto creando una clase interna privada llamada PlaylistIterator que implemente tu interfaz Iterator. Este iterador interno mantiene su propia posición de índice y recorre el arreglo de canciones, devolviendo cada canción en orden.

  • Song.java: Crea una clase Song simple que envuelva el título de una canción. Debe tener un constructor que reciba el título (String), un método getTitle() y un método toString() que devuelva "Playing: " + title.
  • Main.java: ¡Une todo tu sistema de iterador! Recibirás una entrada: una lista de títulos de canciones separada por comas (por ejemplo: "Bohemian Rhapsody,Stairway to Heaven,Hotel California").

    Crea una Playlist con capacidad para 10 canciones. Procesa la entrada y añade cada título de canción a la lista de reproducción. Luego obtén un iterador de la lista de reproducción y úsalo para recorrer todas las canciones, imprimiendo cada una envuelta en un objeto Song (que se mostrará como "Playing: " + title).

    Después de iterar por todas las canciones, imprime "Playlist complete!" en una nueva línea.

Recibirás una entrada: una cadena de títulos de canciones separada por comas.

Por ejemplo, con la entrada "Yesterday,Imagine,Let It Be", tu salida sería:

Playing: Yesterday
Playing: Imagine
Playing: Let It Be
Playlist complete!

¡Observa cómo tu clase Main utiliza los métodos hasNext() y next() del iterador para recorrer la lista de reproducción sin saber nada sobre la estructura del arreglo subyacente! El iterador encapsula toda la lógica de recorrido, ¡manteniendo la representación interna de la colección oculta del código del cliente!

Hoja de referencia

El Patrón Iterator es un patrón de diseño de comportamiento que proporciona una forma de acceder a los elementos de una colección de manera secuencial sin exponer su estructura subyacente.

El patrón separa la lógica de recorrido de la propia colección utilizando dos componentes principales:

  • Interfaz Iterator: define métodos para recorrer los elementos
  • Iterable/Contenedor: crea iteradores para su colección

Estructura Básica

interface Iterator<T> {
    boolean hasNext();
    T next();
}

interface Container<T> {
    Iterator<T> createIterator();
}

Ejemplo de Implementación

class BookShelf implements Container<String> {
    private String[] books;
    private int count = 0;
    
    public BookShelf(int size) {
        books = new String[size];
    }
    
    public void addBook(String book) {
        books[count++] = book;
    }
    
    public Iterator<String> createIterator() {
        return new BookIterator();
    }
    
    private class BookIterator implements Iterator<String> {
        private int index = 0;
        
        public boolean hasNext() {
            return index < count;
        }
        
        public String next() {
            return books[index++];
        }
    }
}

Uso

BookShelf shelf = new BookShelf(3);
shelf.addBook("Design Patterns");
shelf.addBook("Clean Code");

Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

El iterador mantiene su propio estado de recorrido, lo que permite que múltiples iteradores recorran la misma colección de forma independiente. Las interfaces integradas Iterable e Iterator de Java siguen este patrón, permitiendo el uso de bucles for mejorados.

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Crear una Playlist con capacidad para 10 canciones
        
        // TODO: Analizar la entrada (separada por comas) y añadir cada título de canción a la playlist
        
        // TODO: Obtener un iterador de la playlist usando createIterator()
        
        // TODO: Usar el iterador para recorrer todas las canciones
        // Para cada canción, envolverla en un objeto Song e imprimirla
        
        // TODO: Imprimir "Playlist complete!" después de iterar por todas las canciones
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos