Iterator (model de proiectare)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 9 mai 2016; verificările necesită 9 modificări .
iterator
Iterator
Tip de comportamental
Descris în Design Patterns da

Iteratorul  este un model de design comportamental . Reprezintă un obiect care permite accesul secvenţial la elementele unui obiect agregat fără a utiliza descrieri ale fiecăruia dintre obiectele agregate.

De exemplu, elemente precum un arbore , o listă legată , un tabel hash și o matrice pot fi parcurse (și modificate) folosind un obiect Iterator .

Iterarea prin elemente este făcută de obiectul iterator, nu de colecția în sine. Acest lucru simplifică interfața și implementarea colecției și promovează o separare mai logică a preocupărilor .

O caracteristică a unui iterator complet implementat este că codul care utilizează iteratorul poate să nu știe nimic despre tipul agregatului iterat.

Desigur, (în C++) aproape orice agregat poate fi repetat cu un pointer void*, dar:

Iteratoarele vă permit să abstrageți tipul și terminatorul unui agregat folosind Next polimorful (adesea implementat ca operator++ în C++) și agregatul polimorf.end() care returnează „sfârșitul agregatului”.

Astfel, devine posibil să se lucreze cu game de iteratoare, în absența cunoștințelor despre tipul de agregat iterat. De exemplu:

Iterator itBegin = agregat . începe (); Iterator itEnd = agregat . sfârşitul (); func ( itBegin , itEnd );

Și mai departe:

void func ( Iterator itBegin , Iterator itEnd ) { pentru ( Iterator it = itBegin , it != itEnd ; ++ it ) { } }

Exemple

C#

Text sursă în C# /* exemplu de cod în C# Acest cod structural demonstrează modelul Iterator care oferă o modalitate de a parcurge (itera) o colecție de articole fără a detalia structura de bază a colecției. */ ascunde codul // Model iterator -- Exemplu structural folosind System ; folosind System.Collections ; namespace DoFactory.GangOfFour.Iterator.Structural { /// <summary> /// Clasa de pornire MainApp pentru Structural /// Iterator Design Pattern. /// </summary> class MainApp { /// <summary> /// Punct de intrare în aplicația consolă. /// </summary> static void Main () { ConcreteAggregate a = new ConcreteAggregate (); a [ 0 ] = „Articol A” ; a [ 1 ] = „Articol B” ; a [ 2 ] = „Articol C” ; a [ 3 ] = „Articol D” ; // Creați Iterator și furnizați ConcreteIterator agregat i = new ConcreteIterator ( a ); Consola . WriteLine ( "Iterarea peste colecție:" ); obiect obiect = i . primul (); în timp ce (! i . IsDone ()) { Consolă . WriteLine ( element ); item = i . următorul (); } // Așteptați Consola utilizatorului . ReadKey (); } } /// <summary> /// Clasa abstractă „Aggregate” /// </summary> abstract class Aggregate { public abstract Iterator CreateIterator (); public abstract int Număr { get ; set protejat ; } obiect abstract public this [ int index ] { get ; set ; } } /// <summary> /// Clasa 'ConcreteAggregate' /// </summary> clasa ConcreteAggregate : Aggregate { private readonly ArrayList _items = new ArrayList (); public override Iterator CreateIterator () { return new ConcreteIterator ( this ); } // Obține numărul de articole public override int Count { get { return _items . numără ; } set protejat { } } // Indexator public override obiect this [ int index ] { get { return _items [ index ]; } set { _items . inserare ( index , valoare ); } } } /// <summary> /// Clasa abstractă 'Iterator' /// </summary> abstract class Iterator { obiect abstract public First (); obiect abstract public Next (); public abstract bool IsDone (); obiect abstract public CurrentItem (); } /// <summary> /// Clasa 'ConcreteIterator' /// </summary> class ConcreteIterator : Iterator { private readonly Aggregate _aggregate ; private int _current ; // Constructor public ConcreteIterator ( Agregat agregat ) { this . _agregat = agregat ; } // Obține primul element de iterație public override object First () { return _aggregate [ 0 ]; } // Obține următoarea iterație element public override object Next () { object ret = null ; _actual ++; if ( _current < _aggregate . Count ) { ret = _aggregate [ _current ]; } return ret ; } // Obține elementul de iterație curent public override object CurrentItem () { return _aggregate [ _current ]; } // Obține dacă iterațiile sunt complete public override bool IsDone () { return _current >= _aggregate . numără ; } } } Ieșire Repetare peste colecție : Element A Element B Element C Element D

PHP5

Cod sursă PHP5 /** * Modelul iterator oferă un mecanism de iterare prin elementele unei colecții fără a expune implementarea colecției. * * Iterarea prin elemente este făcută de obiectul iterator, nu de colecția în sine. * Acest lucru simplifică interfața și implementarea colecției și, de asemenea, contribuie la o distribuție mai logică a responsabilităților. */ namespace iterator1 { /** * A avea o interfață comună este convenabilă pentru client deoarece clientul este decuplat de implementarea colecției de obiecte. * * ConcreteAggregate conține o colecție de obiecte și implementează o metodă care returnează un iterator pentru această colecție. */ interface IAggregate { /** * Fiecare aromă ConcreteAggregate este responsabilă pentru crearea unei instanțe Concrete Iterator care * poate fi folosită pentru a itera colecțiile sale de obiecte. */ funcția publică createIterator (); } /** * Interfața Iterator trebuie implementată de toți iteratorii. * * ConcreteIterator este responsabil pentru gestionarea poziției curente de iterație. */ interface IIterator { /** * @abstract * @return boolean există un element următor în colecție */ public function hasNext (); /** * @abstract * @return mixed next array element */ public function next (); /** * Îndepărtează elementul curent al colecției * @abstract * @return void */ public function remove (); } /** * În exemplul meu, ambele colecții folosesc același iterator - un iterator de matrice. */ clasa ConcreteAggregate1 implementează IAggregate { /** * @var Item[] $items */ public $items = array (); public function __construct () { $this -> items = array ( nou Item ( 1 , 2 ), nou Item ( 1 , 2 ), nou Item ( 1 , 2 ), ); } public function createIterator () { return new ConcreteIterator1 ( $this -> items ); } } clasa ConcreteAggregate2 implementează IAggregate { /** * @var Item[] $items */ public $items = array (); public function __construct () { $this -> items = array ( nou Item ( 2 , 3 ), nou Item ( 2 , 3 ), nou Item ( 2 , 3 ), ); } public function createIterator () { return new ConcreteIterator1 ( $this -> items ); } } clasa ConcreteIterator1 implementează IIterator { /** * @var Item[] $items */ protected $items = array (); /** * @var int $position stochează poziția curentă de iterație în matrice */ public $position = 0 ; /** * @param $items matrice de obiecte pe care să le iterați peste */ public function __construct ( $items ) { $this -> items = $items ; } funcția publică areNext () { dacă ( $acest -> poziție >= număr ( ​​$acest -> articole ) || număr ( ​​$acest -> articole ) == 0 ) { return ( fals ); } else { return ( adevărat ); } } public function next () { $menuItem = $this -> items [ $this -> position ]; $acest -> poziție ++ ; return ( $menuItem ); } public function remove () { if ( $this -> position <= 0 ) { throw new \Exception ( 'Nu poți apela remove înainte ca cel puțin un next() să fi fost apelat' ); } if ( $acest -> elemente [ $acest -> poziție - 1 ] != nul ) { pentru ( $i = $acest -> poziție - 1 ; $i < număr ( ​​$acest -> articole ); $i + + ) { $this -> items [ $i ] = $this -> items [ $i + 1 ]; } $this -> items [ count ( $this -> items ) - 1 ] = null ; } } } class Client { /** * @var ConcreteAggregate1 $aggregate1 */ public $aggregate1 ; /** * @var ConcreteAggregate2 $aggregate2 */ public $aggregate2 ; function public __construct ( $ agregat1 , $agregat2 ) { $acest -> agregat1 = $agregat1 ; $acest -> agregat2 = $agregat2 ; } public function printAggregatesItems () { $iterator1 = $this -> aggregate1 -> createIterator (); echo " \ nPrimul" ; $this -> printIteratorItems ( $iterator1 ); $iterator2 = $this -> aggregate2 -> createIterator (); echo " \n\ nAl doilea" ; $this -> printIteratorItems ( $iterator2 ); } /** * @param $iterator IIterator */ private function printIteratorItems ( $iterator ) { while ( $iterator -> hasNext ()) { $item = $iterator -> urmatorul (); echo " \n $articol->nume $articol->preț $articol->descriere " ; } } } class Item { public $price ; public $nume ; public $descriere ; function public __construct ( $nume , $pret , $descriere = '' ) { $acest -> nume = $nume ; $acest -> preț = $preț ; $this -> description = $descriere ; } } $runner = client nou ( nou ConcreteAggregate1 (), nou ConcreteAggregate2 ()); $runner -> printAggregatesItems (); }

Exemplu de iterator PHP5 builder

Cod sursă iterator PHP5 builder /** * Model de compozitor cu iterator extern * Iteratorul folosește recursiunea pentru a itera prin arborele de elemente */ namespace compositeIterator { /** * Clientul folosește interfața AComponent pentru a lucra cu obiecte. * Interfața AComponent definește interfața pentru toate componentele: atât combinații, cât și nodurile frunză. * AComponent poate implementa comportamentul implicit pentru add() remove() getChild() și alte operațiuni */ abstract class AComponent { public $customPropertyName ; public $customPropertyDescription ; /** * @param AComponent $component */ public function add ( $component ) { throw new \Exception ( "Operatie nesuportata" ); } /** * @param AComponent $component */ public function remove ( $component ) { throw new \Exception ( "Operatie nesuportata" ); } /** * @param int $int */ public function getChild ( $int ) { throw new \Exception ( "Operatie nesuportata" ); } /** * @return IPhpLikeIterator */ funcția abstractă createIterator (); public function operation1 () { throw new \Exception ( "Operatiune nesuportata" ); } } /** * Leaf moștenește metodele add() remove() getChild(, care ar putea să nu aibă sens pentru un nod frunză. * Deși un nod frunză poate fi considerat un nod cu zero copii * * Frunza definește comportamentul elementelor din o combinație. Pentru a face acest lucru, implementează operațiunile suportate de interfața Composite */ class Leaf extends AComponent { public function __construct ( $nume , $descriere = '' ) { $this -> customPropertyName = $name ; $this -> customPropertyDescription = $descriere ; } public function createIterator () { return new NullIterator (); } public function operation1 () { echo ( " \n Sunt frunza { $this -> customPropertyName } , nu vreau sa fac operatia 1. { $this -> customPropertyDescription } " ); } } clasa NullIterator implementează IPhpLikeIterator { public function valid () { return ( false ); } public function next () { return ( false ); } public function current () { return ( null ); } public function remove () { throw new \CException ( 'operațiune nesuportată' ); } } /** * Interfața Composite definește comportamentul componentelor care au copii și asigură stocarea acestora. * * Compozitul implementează și operațiuni legate de frunze. Unele dintre ele nu pot să nu aibă sens pentru combinații; în astfel de cazuri se aruncă o excepție. */ class Composite extinde AComponent { privat $_iterator = null ; /** * @var \ArrayObject AComponent[] $componente pentru a stoca copii de tip AComponent */ public $components = null ; function public __construct ( $nume , $descriere = '' ) { $this -> customPropertyName = $nume ; $this -> customPropertyDescription = $descriere ; } /** * @param AComponent $component */ public function add ( $component ) { if ( is_null ( $this -> components )) { $this -> components = new \ArrayObject ; } $this -> components -> append ( $component ); } public function remove ( $component ) { foreach ( $this -> componente ca $i => $c ) { if ( $c === $component ) { unset ( $this -> componente [ $i ]); } } } function public getChild ( $int ) { return ( $this -> componente [ $int ]); } public function operation1 () { echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; ecou " \n --------------------------------" ; $iterator = $this -> componente -> getIterator (); while ( $iterator -> valid ()) { $component = $iterator -> curent (); $componenta -> operatiune1 (); $iterator -> următorul (); } } /** * @return CompositeIterator */ public function createIterator () { if ( is_null ( $this -> _iterator )) { $this -> _iterator = new CompositeIterator ( $this -> componente -> getIterator ()); } return ( $this -> _iterator ); } } /** * Iterator recursiv compus */ clasa CompositeIterator implementează IPhpLikeIterator { public $stiva = matrice (); /** * @param \ArrayIterator $componentsIterator */ public function __construct ( $componentsIterator ) { //$this->stack= new \ArrayObject; $this -> stack [] = $componentsIterator ; } public function remove () { throw new \CException ( 'operațiune nesuportată' ); } function public valid () { if ( empty ( $this -> stack )) { return ( false ); } else { /** @var $componentsIterator \ArrayIterator */ // obține primul element $componentsIterator = array_shift ( array_values ​​​​( $this -> stack )); if ( $componentsIterator -> valid ()) { return ( true ); } else { array_shift ( $this -> stack ); return ( $this -> valid ()); } } } public function next () { /** @var $componentsIterator \ArrayIterator */ $componentsIterator = curent ( $this -> stack ); $component = $componentsIterator -> curent (); if ( $component instanceof Composite ) { array_push ( $this -> stack , $component -> createIterator ()); } $componentsIterator -> next (); //return($component); } funcția publică curent () { dacă ( $this -> valid ()) { /** @var $componentsIterator \ArrayIterator */ // obține primul element $componentsIterator = array_shift ( array_values ​​​​( $this -> stack )) ; return ( $componentsIterator -> curent ()); } else { return ( null ); } } } /** * Interfața Iterator trebuie implementată de toți iteratorii. * Această interfață face parte din interfața standard php iterator. * Un anumit Iterator este responsabil pentru gestionarea poziției curente de iterație într-o anumită colecție. */ interface IPhpLikeIterator { /** * @abstract * @return boolean este elementul curent */ public function valid (); /** * @abstract * @return mixt muta cursorul mai departe */ public function next (); /** * @abstract * @return mixed obține elementul curent */ public function current (); /** * elimina elementul curent al colecției * @abstract * @return void */ public function remove (); } clasă Client { /** * @varAComponent */ public $topItem ; function public __construct ( $topItem ) { $this -> topItem = $topItem ; } public function printOperation1 () { $this -> topItem -> operation1 (); } public function printOperation2 () { echo " \n\n\n " ; $iterator = $this -> topItem -> createIterator (); while ( $iterator -> valid ()) { /** @var $component AComponent */ $component = $iterator -> curent (); if ( strstr ( $component -> customPropertyName , 'leaf1' )) { echo ( " \n Sunt Client, am găsit frunza { $component -> customPropertyName } , o voi lăsa aici (pentru "primul meu- colecția de ceai a frunzelor). { $component -> customPropertyDescription } " ); } $iterator -> următorul (); } } } class Test { public static function go () { $a = new Composite ( "c1" ); $b = nou Compozit ( "c2" ); $c = nou Compozit ( "c3" ); $topItem = nou Compozit ( "articol de sus" ); $topItem -> adaugă ( $a ); $topItem -> adaugă ( $b ); $topItem -> adaugă ( $c ); $a -> adaugă ( frunză nouă ( "c1-leaf1" )); $a -> adaugă ( frunză nouă ( "c1-leaf2" )); $b -> adaugă ( frunză nouă ( "c2-leaf1" )); $b -> adaugă ( frunză nouă ( "c2-leaf2" )); $b -> adaugă ( frunză nouă ( "c2-leaf3" )); $c -> adaugă ( frunză nouă ( "c3-leaf1" )); $c -> adaugă ( frunză nouă ( "c3-leaf2" )); $client = client nou ( $topItem ); $client -> printOperation1 (); $client -> printOperation2 (); } } test :: du-te (); }

Python

Cod sursă în Python din abc import ABCMeta , abstractmethod Iterator de clasă ( metaclasă = ABCMeta ): """ Iterator abstract """ _error = None # clasa erorii care este aruncată dacă colecția este în afara limitelor def __init__ ( self , collection , cursor ): """ Constructor. :param collection: colecția care trebuie străbătută de iterator :param cursor: poziția inițială a cursorului în colecția (cheie) """ self ._collection = colecție self ._cursor = cursor @abstractmethod def current ( self ): """ Returnează elementul curent indicat de trecerea iteratorului " "" @abstractmethod def next ( self ): """ Mutați cursorul la următorul element din colecție și returnați-l """ pass @abstractmethod def has_next ( self ): """ Verificați dacă următorul element al colecției există """ trece @abstractmethod def remove ( self ): """ Eliminați elementul curent al colecției indicat de cursorul """ trece def _raise_key_exception ( self ): """ Ridicați un index nevalid conținut în cursorul """ raise self . _error ( „Colecția clasei {} nu are cheia „ {} ”’ . format ( self . __class__ . __name__ , self . _cursor )) class ListIterator ( Iterator ): """ Un iterator care iterează peste o listă normală """ _error = IndexError def __init__ ( self , collection : list ): super () . __init__ ( colecție , 0 ) def curent ( self ): if self . _cursor < len ( self . _collection ): return self . _colecție [ self . _cursor ] self . _raise_key_exception () def next ( self ): if len ( self . _collection ) >= self . _cursor + 1 : sine . _cursor += 1 returnează sine . _colecție [ self . _cursor ] self . _raise_key_exception () def are_next ( self ): return len ( self . _collection ) >= self . _cursor + 1 def remove ( self ): if 0 <= self . _cursor < len ( self . _collection ): self . _colecție . elimina ( self . _colecție [ self . _cursor ]) else : self . _raise_key_exception () clasa DictIterator ( Iterator ): """ Iterator de dicționar - datorită faptului că dicționarele în Python sunt implementate ca tabele hash, ordinea de traversare se poate schimba în timpul diferitelor rulări """ _error = KeyError def __init__ ( self , collection : dict ): super () . __init__ ( colecție , următor ( iter ( colecție ))) sine . _keys = listă ( self . _colecție . chei ()) self . _chei . pop ( 0 ) def curent ( self ): if self . _cursor în sine . _colecție : return self . _colecție [ self . _cursor ] self . _raise_key_exception () def next ( self ): if len ( self . _keys ): self . _cursor = self . _chei . pop ( 0 ) return self . _colecție [ self . _cursor ] else : sine . _raise_key_exception () def are_next ( self ): return len ( self . _keys ) > 0 def remove ( self ): dacă self . _cursor în sine . _colecție : del self . _colecție [ self . _cursor ] try : self . următorul () cu excepția sinelui . _error : ridicați KeyError ( 'Colecția de tip {} este goală' . format ( self . __class__ . __name__ )) else : self . _raise_key_exception () Class Collection ( metaclass = ABCMeta ): """ Colecție abstractă """ @abstractmethod def iterator ( self ): trece class ListCollection ( Collection ): """ O colecție wrapper pentru o listă normală """ def __init__ ( self , collection : list ): self . _colecție = colecție def iterator ( self ): returnează ListIterator ( self . _collection ) clasa DictCollection ( Colecție ): """ Colecție Wrapper pentru dicționar """ def __init__ ( self , collection : dict ): self . _colecție = colecție def iterator ( self ): return DictIterator ( self . _collection ) def test ( title = str , collection = Collection ): print ( " \n {} \n " . format ( title )) iterator = collection . iterator () print ( iterator . curent ()) iterator . următorul () print ( iterator . următorul ()) iterator . elimina () print ( iterator . curent ()) print ( iterator . are_next ()) imprimare () if __name__ == '__main__' : print ( 'OUTPUT:' ) test ( 'Testarea listei' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ])) test ( 'Testarea dictionarului' , DictCollection ({ 'a' : 1 , „b” : 2 , „c” : 3 , „f” : 8 })) ''' IEȘIRE: Lista de testare 1 3 4 Adevărat Dicţionar testing 1 3 2 Fals '''

Rugina

Exemplu de rugina #[deriva (Depanare, Clonare, Copiere)] pub struct ExampleRange { începe : i64 , curent : i64 , sfârşit : i64 , } impl ExampleRange { pub fn new ( început : i64 , sfârșit : i64 ) -> Self { ExampleRange { incepe , curent : începe , sfarsit , } } pub fn iter ( & self ) -> ExampleRange { * sine } } utilizați std :: fmt ; impl fmt :: Afișează pentru ExampleRange { fn fmt ( & self , f : & mut fmt :: Formatter <' _ > ) -> fmt :: Rezultat { scrie! ( f , " {} " , sine . curent ) } } impl Iterator pentru ExampleRange { typeItem = i64 ; _ fn next ( & mut self ) -> Opțiune < Self :: Item > { dacă sine . curent < sine . Sfârşit { ( Unii ( self . current ), self . current += 1 ). 0 } altfel { Nici unul } } fn last ( mut self ) -> Opțiune < Self :: Item > { dacă sine . curent > sine . ÎNCEPE { ( self . current -= 1 , Unii ( self . current )). unu } altfel { Nici unul } } } fn principal () { let it = ExampleRange :: new ( 0 , 6 ); pentru elementul din el { println! ( "{}" , element ); } } ''' IEȘIRE : 0 unu 2 3 patru 5 '''