
Iterator
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()etemProxima(); - 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.
Problema
Seção intitulada “Problema”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.
Solução
Seção intitulada “Solução”O Iterator propõe:
- Definir uma interface Iterator, com:
temProxima(): ainda há elementos?proxima(): devolve o atual e avança.
- Criar um ConcreteIterator, que conhece a coleção e guarda a posição.
- Definir o Aggregate (a coleção), com um método
criarIterador(). - O cliente percorre pela interface, sem ver a estrutura interna.
Assim, a travessia sai da coleção e vira uma responsabilidade própria.
Estrutura (papéis)
Seção intitulada “Estrutura (papéis)”- 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
Exemplo completo em Java (didático)
Seção intitulada “Exemplo completo em Java (didático)”Iterator
Seção intitulada “Iterator”public interface IteradorPlaylist { boolean temProxima(); String proxima();}Concrete Iterator
Seção intitulada “Concrete Iterator”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++); }}Aggregate
Seção intitulada “Aggregate”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); }}Uso (cliente)
Seção intitulada “Uso (cliente)”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()eproxima(); - para embaralhar, basta um novo iterador;
- a
Playlistpode mudar de estrutura sem quebrar o cliente.
Aplicabilidade (quando usar)
Seção intitulada “Aplicabilidade (quando usar)”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.Iteratore ofor-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.
Contras
Seção intitulada “Contras”- 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.
Relações com outros padrões
Seção intitulada “Relações com outros padrões”- 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, implementarIterableaplica 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.