Pular para o conteúdo
GoF Padrões de Projeto Comportamentais
Comportamental escopo de objeto
GoF, p. 257 também chamado de Cursor

Iterador

Iterator

Percorra uma coleção sem saber como ela é feita por dentro.

Complexidade simples Frequência de uso muito comum
Intençãocomo o livro define

Fornecer uma maneira de acessar sequencialmente os elementos de um objeto agregado sem expor sua representação subjacente.

Analogiauma imagem do mundo real

Formas de visitar uma cidade

Você pode andar a esmo, seguir um app de mapas ou contratar um guia. Cada um é uma estratégia de percurso sobre a mesma cidade, e nenhuma exige que você entenda o plano diretor urbano. Trocar de guia não muda a cidade; e dois turistas podem percorrê-la ao mesmo tempo, cada um no seu ponto.

O problema

Coleções guardam dados de formas muito diferentes (array, lista ligada, árvore, grafo, páginas de uma API). Colocar todos os algoritmos de percurso dentro da coleção a incha e quebra sua responsabilidade principal — e o cliente que percorre acaba dependendo da estrutura interna.

A solução

Extraia o percurso para um objeto iterador separado, com uma interface uniforme (`próximo()`, `temPróximo()`). Cada iterador guarda sua própria posição, o que permite vários percursos simultâneos e independentes sobre a mesma coleção.

Sintomascomo reconhecer no seu código
  • O cliente acessando colecao.itensInternos[i] diretamente.
  • Métodos percorrerAssim() e percorrerAssado() inchando a classe da coleção.

Estrutura

criaClient«interface»Colecao+ criarIterador()«interface»Iterador+ proximo()+ temProximo()ArvoreBinariaEmOrdemEmLargura
Fig. 16 — Iterator herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
Iterator
Interface de percurso: próximo, tem próximo, valor atual.
ConcreteIterator
Implementa um algoritmo de percurso e guarda a posição.
Aggregate
Interface que declara um método para obter um iterador.
ConcreteAggregate
A coleção; devolve o iterador apropriado (Factory Method).

Implementação

Listagem 16 Dois percursos sobre a mesma árvore + paginação preguiçosa
class No { constructor(v, esq = null, dir = null) { Object.assign(this, { v, esq, dir }); } }

class Arvore {
  constructor(raiz) { this.raiz = raiz; }

  // Em JavaScript, iteradores são de primeira classe: geradores + Symbol.iterator.
  *emOrdem(no = this.raiz) {
    if (!no) return;
    yield* this.emOrdem(no.esq);
    yield no.v;
    yield* this.emOrdem(no.dir);
  }

  *emLargura() {
    const fila = [this.raiz];
    while (fila.length) {
      const no = fila.shift();
      if (!no) continue;
      yield no.v;
      fila.push(no.esq, no.dir);
    }
  }

  // O percurso padrão da coleção:
  [Symbol.iterator]() { return this.emOrdem(); }
}

const arvore = new Arvore(new No(8, new No(3, new No(1), new No(6)), new No(10, null, new No(14))));

console.log([...arvore.emOrdem()]);    // [1, 3, 6, 8, 10, 14]
console.log([...arvore.emLargura()]);  // [8, 3, 10, 1, 6, 14]
for (const v of arvore) { /* usa o percurso padrão, sem conhecer a estrutura */ }

// ── Iterador PREGUIÇOSO sobre uma API paginada ────────
async function* todosOsUsuarios(fetchPagina) {
  let pagina = 1, resultado;
  do {
    resultado = await fetchPagina(pagina++);   // só busca quando o consumidor pede
    yield* resultado.itens;
  } while (resultado.temMais);
}
// for await (const u of todosOsUsuarios(api)) { … }  ← milhões de itens, memória constante
Na práticaonde ele já existe
  • java.util.Iterator e todo o Java Collections Framework
  • Symbol.iterator, generators e for..of no JavaScript
  • __iter__ do Python; IEnumerable/IEnumerator do C#

Consequências

A favor
  • Limpa a coleção e o cliente (Responsabilidade Única).
  • Novos percursos e novas coleções entram independentemente (Aberto/Fechado).
  • Vários percursos simultâneos, cada um com sua posição.
  • Permite pausar e retomar o percurso; viabiliza sequências infinitas e preguiçosas.
Contra
  • Exagero para coleções simples — um `for` direto é mais claro.
  • Pode ser menos eficiente que percorrer a estrutura diretamente.
Use quando
  • A estrutura interna da coleção é complexa e você quer escondê-la.
  • Você precisa de vários tipos de percurso sobre a mesma coleção.
  • Você quer uma interface de percurso uniforme sobre coleções diferentes.
  • Os dados são grandes demais para caber na memória (streams, paginação).
Evite quando
  • Você só percorre um array simples do começo ao fim.

Relações com outros padrões

costuma andar junto
Composite
Iterators são a forma natural de percorrer árvores Composite.
Factory Method
A coleção usa um Factory Method para devolver o iterador certo.
Memento
Um memento pode capturar o estado de um iterador para retomá-lo depois.
Visitor
Iterator percorre; Visitor decide o que fazer em cada nó.

Verificação

Questãoa resposta está marcada

Por que o estado do percurso fica no ITERADOR e não na coleção?

  1. Para permitir vários percursos simultâneos e independentes sobre a mesma coleção
  2. Porque coleções não podem ter campos mutáveis
  3. Para reduzir o consumo de memória da coleção
  4. Porque a linguagem exige isso

Se a posição morasse na coleção, dois laços aninhados sobre ela interfeririam um no outro. Iteradores independentes resolvem isso.