Menu
Coddy logo textTech

Padrão Iterator

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 76 de 87.

O Iterator Pattern é um padrão de design comportamental que fornece uma maneira de acessar elementos de uma coleção sequencialmente sem expor sua estrutura subjacente. Esteja você trabalhando com um array, lista encadeada ou árvore, o iterador oferece uma maneira uniforme de percorrer os elementos.

O padrão separa a lógica de travessia da própria coleção. Ele envolve dois componentes principais: uma interface Iterator que define métodos para percorrer elementos, e um Iterable (ou Aggregate) que cria iteradores para sua coleção:

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++];
        }
    }
}

O iterador mantém seu próprio estado de iteração, permitindo que múltiplos iteradores percorram a mesma coleção de forma independente. Os clientes usam o iterador sem saber como a coleção armazena seus dados:

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());
}

As interfaces integradas Iterable e Iterator do Java seguem exatamente este padrão, razão pela qual você pode usar loops for aprimorados com qualquer classe que implemente Iterable. O Padrão Iterator é essencial quando você precisa fornecer múltiplos métodos de travessia ou ocultar estruturas internas complexas do código do cliente.

challenge icon

Desafio

Fácil

Vamos construir um sistema de playlist usando o Iterator Pattern! Você criará uma playlist de música que armazena músicas e fornece um iterador personalizado para percorrê-las sequencialmente — sem expor como as músicas são armazenadas internamente. Este é um caso de uso perfeito para o Iterator Pattern, permitindo que os usuários naveguem em sua coleção por meio de uma interface limpa e uniforme.

Você organizará seu código em quatro arquivos:

  • Iterator.java: Defina sua interface genérica Iterator<T> com dois métodos: hasNext() que retorna um booleano indicando se existem mais elementos, e next() que retorna o próximo elemento do tipo T.
  • Playlist.java: Crie a classe agregada que contém suas músicas. Sua Playlist deve armazenar músicas em um array de String com uma capacidade fixa (passada para o construtor) e rastrear quantas músicas foram adicionadas. Inclua um método addSong(String song) para adicionar músicas à playlist.

    Sua Playlist precisa de um método createIterator() que retorne um Iterator<String>. Implemente isso criando uma classe interna privada chamada PlaylistIterator que implementa sua interface Iterator. Este iterador interno mantém sua própria posição de índice e percorre o array de músicas, retornando cada música em ordem.

  • Song.java: Crie uma classe Song simples que envolve o título de uma música. Ela deve ter um construtor que recebe o título (String), um método getTitle() e um método toString() que retorna "Playing: " + title.
  • Main.java: Reúna seu sistema de iterador! Você receberá uma entrada: uma lista de títulos de músicas separados por vírgula (por exemplo: "Bohemian Rhapsody,Stairway to Heaven,Hotel California").

    Crie uma Playlist com capacidade para 10 músicas. Analise a entrada e adicione cada título de música à playlist. Em seguida, obtenha um iterador da playlist e use-o para percorrer todas as músicas, imprimindo cada uma envolvida em um objeto Song (que será exibido como "Playing: " + title).

    Após iterar por todas as músicas, imprima "Playlist complete!" em uma nova linha.

Você receberá uma entrada: uma string de títulos de músicas separados por vírgula.

Por exemplo, com a entrada "Yesterday,Imagine,Let It Be", sua saída seria:

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

Observe como sua classe Main usa os métodos hasNext() e next() do iterador para percorrer a playlist sem saber nada sobre a estrutura do array subjacente. O iterador encapsula toda a lógica de travessia, mantendo a representação interna da coleção oculta do código do cliente!

Folha de consulta

O Iterator Pattern (Padrão Iterator) é um padrão de projeto comportamental que fornece uma maneira de acessar elementos de uma coleção sequencialmente sem expor sua estrutura subjacente.

O padrão separa a lógica de travessia da própria coleção usando dois componentes principais:

  • Interface Iterator: define métodos para percorrer elementos
  • Iterable/Container: cria iteradores para sua coleção

Estrutura Básica

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

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

Exemplo de Implementação

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());
}

O iterador mantém seu próprio estado de travessia, permitindo que múltiplos iteradores percorram a mesma coleção de forma independente. As interfaces integradas Iterable e Iterator do Java seguem este padrão, habilitando loops for aprimorados (enhanced for-loops).

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Crie uma Playlist com capacidade para 10 músicas
        
        // TODO: Analise a entrada (separada por vírgulas) e adicione o título de cada música à playlist
        
        // TODO: Obtenha um iterator da playlist usando createIterator()
        
        // TODO: Use o iterator para percorrer todas as músicas
        // Para cada música, envolva-a em um objeto Song e imprima-o
        
        // TODO: Imprima "Playlist complete!" após iterar por todas as músicas
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos