O padrão Iterator é um padrão de design comportamental que tem como objetivo principal fornecer uma maneira de acessar os elementos de um objeto agregado (como uma coleção) sequencialmente sem expor sua representação interna. O padrão Iterator resolve uma série de problemas:

  1. Acesso Uniforme aos Elementos de uma Coleção: Em sistemas com diferentes tipos de coleções (como listas, árvores, grafos etc.), o Iterator fornece uma interface comum para percorrer essas coleções, independentemente de suas estruturas internas.

  2. Encapsulamento da Lógica de Navegação: O Iterator encapsula a lógica necessária para percorrer uma coleção, separando-a da lógica de negócios. Isso simplifica a interface das coleções e facilita a manutenção.

  3. Suporte a Diferentes Formas de Iteração: O padrão permite a implementação de diferentes tipos de iterações (como reversa, em profundidade para árvores, etc.), sem que o cliente precise conhecer os detalhes da estrutura da coleção.

  4. Uso Simultâneo de Múltiplas Iterações: Permite que várias iterações ocorram simultaneamente em uma mesma coleção sem que uma interfira na outra.

Como Funciona

O padrão Iterator envolve geralmente dois componentes principais:

  • Iterator (Interface ou Classe Abstrata): Define uma interface para acessar e percorrer elementos. Geralmente inclui métodos como next(), hasNext(), e às vezes métodos para remoção.
  • ConcreteIterator: Implementação concreta da interface Iterator. Esta classe sabe como iterar sobre a coleção associada.
  • Aggregate (Interface ou Classe Abstrata): Define uma interface para criar um Iterator.
  • ConcreteAggregate: Implementação concreta da interface Aggregate. Esta classe retorna uma instância de um ConcreteIterator apropriado para a coleção.

Exemplo

Um exemplo comum do uso do padrão Iterator é em bibliotecas de coleções de linguagens de programação, onde o Iterator é usado para percorrer conjuntos, listas e outras estruturas de dados. O padrão Iterator abstrai a complexidade de acesso aos elementos da coleção, permitindo que os desenvolvedores se concentrem na lógica de negócios sem se preocupar com detalhes de implementação da coleção.

Exemplo de Implementação

Vamos criar um exemplo simples do padrão Iterator em Java. Vamos desenvolver um sistema que permite iterar sobre uma coleção de nomes (strings) usando o padrão Iterator.

Interface Iterator

Primeiro, definimos a interface Iterator:

public interface Iterator {
    boolean hasNext();
    Object next();
}

Classe ConcreteIterator

Agora, implementamos o ConcreteIterator para a coleção de nomes:

public class NomeIterator implements Iterator {
    private String[] nomes;
    private int index;
 
    public NomeIterator(String[] nomes) {
        this.nomes = nomes;
    }
 
    @Override
    public boolean hasNext() {
        return index < nomes.length;
    }
 
    @Override
    public Object next() {
        if (this.hasNext()) {
            return nomes[index++];
        }
        return null;
    }
}

Interface Aggregate

Definimos a interface Aggregate que cria um Iterator:

public interface Aggregate {
    Iterator createIterator();
}

Classe ConcreteAggregate

Implementamos a ConcreteAggregate para a coleção de nomes:

public class ColecaoNomes implements Aggregate {
    private String[] nomes;
 
    public ColecaoNomes(String[] nomes) {
        this.nomes = nomes;
    }
 
    @Override
    public Iterator createIterator() {
        return new NomeIterator(nomes);
    }
}

Testando o Padrão Iterator

Finalmente, usamos o padrão Iterator para percorrer a coleção de nomes:

public class Main {
    public static void main(String[] args) {
        String[] nomes = {"Ana", "Bruno", "Carlos", "Diana"};
        ColecaoNomes colecaoNomes = new ColecaoNomes(nomes);
 
        Iterator iterator = colecaoNomes.createIterator();
        
        System.out.println("Nomes na coleção:");
        while (iterator.hasNext()) {
            String nome = (String) iterator.next();
            System.out.println(nome);
        }
    }
}

Neste exemplo, a classe ColecaoNomes é um ConcreteAggregate que mantém uma coleção de nomes e fornece um meio de criar um NomeIterator (ConcreteIterator). O NomeIterator implementa a lógica para percorrer a coleção de nomes. Isso demonstra como o padrão Iterator permite um acesso sequencial e uniforme aos elementos de uma coleção sem expor sua representação interna.