Menu
CoddyTech

Padrão Iterator

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

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

O padrão separa a lógica de percurso da própria coleção. Ele envolve dois componentes principais: uma interface de Iterador que define métodos para percorrer elementos e um Iterável (ou Agregado) 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 percurso, permitindo que vários 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 esse padrão, e é por isso que você pode usar loops for aprimorados com qualquer classe que implemente Iterable. O Padrão Iterator é essencial quando você precisa fornecer vários métodos de travessia ou ocultar estruturas internas complexas do código cliente.

challenge icon

Desafio

Fácil

Vamos criar um sistema de playlists usando o padrão Iterator! Você criará uma playlist de músicas que armazena músicas e fornece um iterador personalizado para percorrê-las em sequência, sem expor como as músicas são armazenadas internamente. Este é um caso de uso perfeito para o padrão Iterator, permitindo que os usuários naveguem pela sua coleção por meio de uma interface simples 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 há mais elementos, e next(), que retorna o próximo elemento do tipo T.
  • Playlist.java: Crie a classe agregadora que contém suas músicas. Sua Playlist deve armazenar músicas em um array de String com capacidade fixa (passada ao construtor) e acompanhar 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 retorna um Iterator<String>. Implemente-o criando uma classe interna privada chamada PlaylistIterator que implementa sua interface Iterator. Esse iterador interno mantém sua própria posição de índice e percorre o array de músicas, retornando cada música na ordem.

  • Song.java: Crie uma classe simples Song que encapsula 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: Junte seu sistema de iteradores! Você receberá uma entrada: uma lista de títulos de músicas separados por vírgulas (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 encapsulada em um objeto Song (que será exibido como Playing: [title]).

    Depois de percorrer todas as músicas, imprima Playlist complete! em uma nova linha.

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

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 percurso, mantendo a representação interna da coleção oculta do código cliente!

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 cada título de música à playlist
        
        // TODO: Obtenha um iterador da playlist usando createIterator()
        
        // TODO: Use o iterador para percorrer todas as músicas
        // Para cada música, encapsule-a em um objeto Song e imprima-o
        
        // TODO: Imprima "Playlist complete!" após percorrer 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

Pratique por conta própria: Compilador de Java online