Nel contesto della programmazione orientata agli oggetti, il termine Iterator (reso in italiano con "iteratore") denota uno dei più comuni e conosciuti design pattern. L'Iterator risolve diversi problemi connessi all'accesso e alla navigazione attraverso gli elementi, in particolare, di una struttura dati contenitrice, senza esporre i dettagli dell'implementazione e della struttura interna del contenitore. L'oggetto principale su cui si basa questo design pattern è l'iteratore.
Una classe contenitrice dovrebbe consentire l'accesso e la navigazione attraverso l'insieme degli elementi che contiene.
Nella programmazione a oggetti, un'alternativa semplice e preferibile all'uso di indici (come accade ad esempio per gli array) consiste nell'aggiungere operazioni all'interfaccia del contenitore. Questa soluzione ha il notevole vantaggio che, se l'interfaccia è ben definita, consente di annullare la dipendenza da dettagli interni del contenitore, ma ciò presenta alcuni inconvenienti:
Il design pattern Iterator, quindi, supera le soluzioni che si possono ottenere con la pura programmazione ad oggetti mediante codice più complesso.
L'idea chiave del pattern Iterator consiste nel trasferire la responsabilità dell'accesso e della navigazione attraverso gli elementi a una classe separata dal contenitore: l'iteratore.
La classe iteratore consente di visitare ad uno ad uno l'insieme degli elementi di un contenitore come se fossero ordinati in una sequenza finita. A questo scopo, un oggetto iteratore deve tenere traccia dell'ultimo elemento visitato e deve essere in grado di calcolare qual è l'elemento successivo nella sequenza di attraversamento.
Per permettere di visitare qualunque aggregato di elementi di un tipo concreto, indipendentemente dall'iteratore specifico e dal contenitore ad esso associato, il pattern Iterator richiede la definizione di due interfacce:
La prima interfaccia è condivisa da tutte le classi contenitore e definisce un'operazione per ottenere un nuovo iteratore della classe stessa; la seconda definisce l'insieme di operazioni comuni ad ogni tipo di iteratore.
Il pattern iterator definisce due gerarchie di classi: una per i contenitori e una per gli iteratori. Le classi contenitore possono essere specializzate per tipo di elemento contenuto o per tipo di struttura in cui gli elementi sono organizzati. Le classi di iteratori sono specializzati per tipo di contenitore (iteratore concreto) e per tipo di navigazione attraverso la sequenza di elementi (iteratori specializzati).
L'adozione del pattern Iterator consente di:
Senza polimorfismo, una classe iteratore è strettamente accoppiata al suo tipo di contenitore e di elementi. Per poter cambiare la classe contenitore senza dover cambiare il codice che ne usufruisce e che attraversa gli elementi contenuti, occorre generalizzare il concetto di iteratore e trasformarlo in un'interfaccia.
Sfruttando le capacità polimorfiche di alcuni linguaggi di programmazione è possibile definire un'unica interfaccia uniforme per tutti i tipi di oggetti iteratore. Questo permette di scrivere programmi in cui l'accesso ai dati contenuti da un aggregato è completamente indipendente dalla struttura dell'aggregato stesso, purché esista una concreta implementazione dell'oggetto iteratore per una data.
Per rendere il pattern Iterator completamente indipendente dall'implementazione concreta, è necessario virtualizzare il processo di creazione delle istanze di iteratori. Di solito si provvede a questa necessità definendo un'operazione dell'interfaccia contenitore per creare un nuovo iteratore ad ogni invocazione.