UGIdotNET Home UGIdotNET Home
UGIdotNET Blogs UGIdotNET Blogs
UGIdotNET Forum UGIdotNET Forum
MSDN Architetti MSDN Architetti
Visualizza Modifiche Visualizza Modifiche
Modifica Modifica
Stampa Stampa
Modifiche Recenti Modifiche Recenti
Sottoscrizioni Sottoscrizioni
Ufficio Oggetti Smarriti Ufficio Oggetti Smarriti
Cerca Riferimenti Cerca Riferimenti
Rinomina Rinomina
Cerca

Versioni

30/01/2007 10.52.33
-85.18.76.234
30/01/2007 10.52.03
-85.18.76.234
05/04/2006 19.47.18
LucaMinudel-193.42.138.33
05/04/2006 19.45.24
LucaMinudel-193.42.138.33
30/12/2005 0.35.46
LucaMinudel-151.47.142.68
Elenco completo versioni Elenco completo versioni
Pattern Iterator
.
Summary Un design pattern che accede agli elementi di una collezione in modo sequenziale.

Conosciuto anche come

Cursor.

Intento

Il design pattern Iterator (ConcreteIterator) accede in modo sequenziale gli elementi di un oggetto aggregato ossia di una collezione (ConcreteAggregate).

La classe ConcreteIterator accede agli elementi a run-time quindi questo design pattern è classificato rispetto allo scopo (vedi ClassificazioneDeiDesignPattern#ClassiOggetti) come rivolto agli oggetti. Rispetto al fine questo design pattern è classificato tra i ClassificazioneDeiDesignPattern#Comportamentali .

Diagramma UML

Un'altro diagramma equivalente qui .

Motivazione

Nella ProgrammazioneObjectOriented la prensenza di oggetti aggregati ossia collezioni di oggetti è un fatto molto frequente e avviene stabilendo una RelazioneDiContenimento tra l'oggetto aggregato ed i suoi elementi. Per questo le collezioni rivestono un ruolo fondamentale in ogni LinguaggioObjectOriented (vedi qui e qui ).

Le collezioni possono essere di vario tipo, un elenco di valori, un elenco di coppie chiave+valore, un albero, una lista concatenata, ect. Diventa fondamentale quindi la possibilità di ciclare in modo sequenziale tra gli elementi della collezione astraendo dalla struttura fisica della specifica collezione sottostante.

Il design pattern Iterator permette di iterare in modo sequenziale le collezioni indipendentemente dalla loro struttura facendosi carico della responsabilità di implementare la logica di iterazione senza bisogno di duplicarla in ogni collezione e di aggiungere ad ogni interfaccia di una collezione i relativi metodi di iterazione (Next, Current, IsDone, ...).

Può essere necessario inoltre che più utilizzatori (Client) iterino la collezione contemporaneamente. Una stessa collezione può anche essere iterata in diversi modi (con ordinamento diverso, con diversi filtri, nel senso opposto, etc.). Il design pattern Iterator assolve anche a queste necessità.

Esempi d'uso in .NET

Tutte le collezioni del .NET Framework (identificate dall'interfaccia ICollection) implementano IEnumerable che è un esempio di PatternFactoryMethod il cui metodo GetEnumerator restituisce appunto un ConcreteIterator ossia un IEnumerator con i metodi:

  • Reset,
  • MoveNext,
  • Current.

Nel .NET 2.0 grazie ai generics (vedi il ParadigmaDiProgrammazioneGenerica) sono disponibili le versioni generiche di queste interfacce che permettono di tipizzare fortemente l'iteratore ossia IEnumerable<T> e IEnumerator<T> dove T rappresenta il tipo dell'elemento ciclato.

Queste collezioni possono essere facilmente ciclate utilizzando il ciclo foreach del C# che fa automaticamente uso del Iterator.

Un altro esempio del design pattern Iterator in .NET è dato dalla classe System.IO.Stream che permette di leggere ma anche di scrivere una sequanza di byte tra cui ad esempio File, dati dalla rete, dati in memoria, Blob dal Db Oracle, etc.

Note sulla implementazione in .NET

In .NET 2.0 e quindi in C#2.0 è inoltre disponibile la keyword yield che implementa velocemente un iteratore per una collezione, cosa che può essere utile in questi casi:

  • il programmatore deve realizzare un metodo la cui elaborazione restituisce una collezione di elementi
  • il programmatore vuole aggiungere ad una classe contenitore la possibilità di ciclare in diversi modi sugli elementi (ad esempio in ordine inverso, oppure su una selezione degli elementi, etc.)
  • il programmatore ha creato una classe contenitore da zero (ad esempio una collezione di elementi Ordine) e vuole aggiungerci la possibilità di ciclare col foreach gli elementi contenuti (ad esempio sulle singole istanze di Ordine).

Ecco un esempio, una collezione di parole:

    class Parole : sysCol.Generic.IEnumerable<string>
    {
        private string[] _parole;


        public Parole(string frase)
        {
            _parole = frase.Split(new char[] {' ', '\t', '\n', '\r', ',', '.', ';'});
        }


        #region Implementazione dell'interfaccia IEnumerable
        public sysCol.Generic.IEnumerator<string> GetEnumerator()
        {
            for (int i = 0; i < _parole.Length; ++i)
                yield return _parole[i];
        }


        sysCol.IEnumerator sysCol.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }


        #endregion 


    }

Del codice .NET di esempio è disponibile qui .

Relazione con altri design pattern

Il design pattern Iterator è usato spesso per ciclare gli elementi di strutture ricorsive come quelle del PatternComposite.

Gli iteratori polimorfici (come IEnumerator e IEnumerator<T>) utilizzanbo spesso il PatternFactoryMethod (come il metodo GetEnumerator di IEnumerable) per istanziare l'iteratore adatto.

Il PatternMemento spesso è usato internamente dal ConcreteIterator per memorizzare lo stato di una iterazione (cosi come fa la keyword yeld del C#2.0).

Vedi la mappa della RelazioneTraDesignPattern.

Approfondimenti

Seguono alcune classificazioni degli iteratori comunemente note dagli sviluppatori Senior che usano un LinguaggioObjectOriented.

Questa classificazione deriva dalla STL (la Standard Templete Library) del C++:

  • Input: iteratore di sola lettura
  • Output: iteratore che permette di scrivere ossia aggiungere o eliminare elementi
  • Forward only: iteratore che permette di iterare gli elementi solo ciclando in avanti
  • Bidirezionale: iteratore che permette di ciclare in entrambe le direzioni (ossia richiedere tanto il Next quanto il Previous)
  • Random Access: iteratori che permetto di accedere all'elemento anche per indice.

In .NET gli iteratori delle collezioni sono di Input e Forward only, alcune collezioni espongono un indexer che è simile ad un iteratore di tipo Random Access. Gli Stream del .NET invece possono essere sia Input che Output e alcuni sono Forward Only mentre altri sono anche Bidirezionali.

Sempre dalla STL esite questa ulteriore classificazione degli iteratori:

  • Const: non è possibile assegnare valori a proprietà o eseguire metodi che modificano gli oggetti acceduti tramite l'iteratore
  • Reverse: è un iteratore che accede agli elementi in ordine inverso.

In .NET gli iteratori non sono Const perché non è implementato il concetto di const in .NET e non esiste una implementazione standard di un iteratore Reverse perché da collezione a collezione l'implementazione efficente del reverse iterator può cambiare (e le funzionalità dei generics di .NET 2.0 non permettono ancora di ottenere questa ottimizzazione mentre i template C++ della STL si).

Infine un iteratore viene classificato come Robust iterator se modificando la collezione mentre la si stà iterando ciò non interferisce con l'iteratore. Gli iteratori di .NET a beneficio delle prestazioni e della occupazione di spazio non sono Robust iterator ma è facile implementare un oggetto che accetta un iteratore standard di .NET e restituisce un iteratore che è pure un Robust iterator.

Un'ultima classificazione differenzia gli iteratori in base a chi controlla l'iterazione:

  • External iterator: quando è l'utilizzatore (il client) che controlla l'iterazione (ossia chiama Next e accede a )
  • Internal iterator: quando è l'iteratore che controlla l'iterazione.

L'iteratore IEnumerator e IEnumerator<T> di .NET sono External iterator infatti hanno i metodi Next e Current che deve chiamare l'utilizzatore o che chiama il foreach per lui. Mentre il metodo ForEach(Action<T> action) di List è un esempio di Internal iterator in cui il programmatore (grazie agli anonymous method con realtiva chiusura del C# 2.0) può agilmente indicare il codice da eseguire per l'azione Action lasciando all'iteratore ForEach il controllo dell'iterazione e l'esecuzione della azione per ogni elemento iterato.

Domande di approfondimento

  • Considera un oggetto Prestito con la proprietà Importo che restituisce l'ammontare del prestito. Dato il requisito di estrarre tutti i prestiti entro un certo intervallo di importi, è una situazione in cui applicare il design pattern Iterator?

Link

VediAnche CatalogoDeiDesignPattern

UGIdotNETWiki

UGIdotNETWiki è il WikiWiki italiano dedicato a .NET

Se è la prima volta che senti parlare di Wiki, leggi il BenvenutoAiVisitatori e WikiInUnMinuto, oppure il ManualePassoPassoDelWiki.

Argomenti Recenti

  • PatternIterator
© 2008 User Group Italiano UGIdotNET. Tutti i diritti riservati. Note legali