Pular para o conteúdo

Iterator é um padrão comportamental que resolve um problema comum: preciso percorrer os elementos de uma coleção sem que o cliente conheça como ela está organizada por dentro.

A ideia é simples:

  • você define uma interface de iterador com proxima() e temProxima();
  • cada travessia concreta vira um iterador que guarda sua própria posição;
  • a coleção (agregado) sabe criar o iterador adequado;
  • o cliente percorre pela interface, um elemento por vez.

Imagine uma playlist de um app de música. Sem o padrão, o cliente acessa a estrutura interna para percorrer as faixas:

public class Playlist {
private final List<String> faixas = new ArrayList<>();
public void adicionar(String faixa) {
faixas.add(faixa);
}
public List<String> getFaixas() { // expõe a estrutura interna
return faixas;
}
}
public class Player {
public void tocarTudo(Playlist playlist) {
List<String> faixas = playlist.getFaixas();
for (int i = 0; i < faixas.size(); i++) {
System.out.println("Tocando: " + faixas.get(i));
}
}
}

Funciona… até a playlist precisar de:

  • novas formas de percorrer (embaralhado, só favoritas);
  • outra estrutura interna (array, nós ligados);
  • dois percursos ao mesmo tempo.

O resultado é travessia espalhada e acoplada:

  • quebra o encapsulamento (o cliente vê a lista interna);
  • trocar a estrutura quebraria o cliente;
  • cada modo de percorrer duplica o laço pelo sistema.

O Iterator propõe:

  1. Definir uma interface Iterator, com:
    • temProxima(): ainda há elementos?
    • proxima(): devolve o atual e avança.
  2. Criar um ConcreteIterator, que conhece a coleção e guarda a posição.
  3. Definir o Aggregate (a coleção), com um método criarIterador().
  4. O cliente percorre pela interface, sem ver a estrutura interna.

Assim, a travessia sai da coleção e vira uma responsabilidade própria.


  • Iterator: interface de travessia (IteradorPlaylist)
  • ConcreteIterator: implementa a travessia e guarda a posição (IteradorSequencial)
  • Aggregate: interface da coleção, com criarIterador()
  • ConcreteAggregate: cria o iterador concreto (Playlist)
  • Client: percorre pela interface, sem conhecer a estrutura

public interface IteradorPlaylist {
boolean temProxima();
String proxima();
}
public class IteradorSequencial implements IteradorPlaylist {
private final List<String> faixas;
private int posicao = 0;
public IteradorSequencial(List<String> faixas) {
this.faixas = faixas;
}
public boolean temProxima() {
return posicao < faixas.size();
}
public String proxima() {
return faixas.get(posicao++);
}
}
public class Playlist {
private final List<String> faixas = new ArrayList<>();
public void adicionar(String faixa) {
faixas.add(faixa);
}
public IteradorPlaylist criarIterador() {
return new IteradorSequencial(faixas);
}
}
public class App {
public static void main(String[] args) {
Playlist playlist = new Playlist();
playlist.adicionar("Faixa A");
playlist.adicionar("Faixa B");
IteradorPlaylist it = playlist.criarIterador();
while (it.temProxima()) {
System.out.println(it.proxima());
}
}
}

Perceba o ponto importante:

  • o cliente só conhece temProxima() e proxima();
  • para embaralhar, basta um novo iterador;
  • a Playlist pode mudar de estrutura sem quebrar o cliente.

Use Iterator quando:

  • For preciso percorrer coleções sem expor a estrutura interna.
  • Houver várias travessias possíveis sobre a mesma coleção.
  • Forem necessários vários iteradores simultâneos e independentes.
  • Você quiser um protocolo uniforme para estruturas diferentes.

Exemplos comuns:

  • java.util.Iterator e o for-each (Iterable);
  • percorrer árvores: pastas, DOM, cenas gráficas;
  • paginação e leitura em streaming;
  • iteradores de banco de dados (cursor por linhas).

  • SRP: a travessia sai da coleção para o iterador.
  • OCP: novas travessias entram sem alterar a coleção.
  • Encapsulamento: o cliente não vê a estrutura interna.
  • Vários iteradores independentes na mesma coleção.
  • Protocolo uniforme para estruturas diferentes.

  • Pode ser overengineering para uma coleção simples e fixa.
  • Mais classes (interface + iteradores concretos).
  • Risco de invalidação ao alterar a coleção durante a travessia.
  • Iteradores internos podem ser menos flexíveis que um laço direto.

  • Composite: o Composite monta a estrutura parte-todo; o Iterator apenas caminha por ela.
  • Visitor: o Iterator percorre sem expor a estrutura; o Visitor adiciona operações sobre os elementos.
  • Iterable + for-each: em Java, implementar Iterable aplica o padrão nos bastidores.

  • Iterator = percorra uma coleção sem expor a estrutura interna.
  • Objetivo principal: isolar a travessia da coleção e do cliente.
  • Ganho prático: várias travessias e iteradores independentes, com um só protocolo.