Iterator (designmønster)

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 9. maj 2016; checks kræver 9 redigeringer .
iterator
Iterator
Type adfærdsmæssige
Beskrevet i Design Patterns Ja

Iterator er  et adfærdsdesignmønster . Repræsenterer et objekt, der tillader sekventiel adgang til elementerne i et aggregeret objekt uden brug af beskrivelser af hvert af de aggregerede objekter.

For eksempel kan elementer som et træ , en sammenkædet liste , en hash-tabel og en matrix krydses (og ændres) ved hjælp af et Iterator- objekt .

Iteration gennem elementerne udføres af iteratorobjektet, ikke af selve samlingen. Dette forenkler grænsefladen og implementeringen af ​​samlingen og fremmer en mere logisk adskillelse af bekymringer .

En funktion ved en fuldt implementeret iterator er, at koden, der bruger iteratoren, muligvis ikke ved noget om typen af ​​det itererede aggregat.

Naturligvis (i C++) kan næsten ethvert aggregat gentages med en void* pointer, men:

Iteratorer giver dig mulighed for at abstrahere typen og terminatoren af ​​et aggregat ved hjælp af den polymorfe Next (ofte implementeret som operator++ i C++) og den polymorfe aggregate.end(), der returnerer "end of the aggregate".

Det bliver således muligt at arbejde med rækker af iteratorer, i mangel af viden om typen af ​​det itererede aggregat. For eksempel:

Iterator itBegin = aggregat . begynde (); Iterator itEnd = aggregat . ende (); func ( itBegin , itEnd );

Og videre:

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

Eksempler

C#

Kildetekst i C# /* eksempelkode i C# Denne strukturelle kode demonstrerer Iterator-mønsteret, som giver mulighed for at krydse (iterere) over en samling af genstande uden at detaljere den underliggende struktur af samlingen. */ skjul kode // Iteratormønster -- Strukturelt eksempel bruger System ; ved hjælp af System.Collections ; navneområde DoFactory.GangOfFour.Iterator.Structural { /// <resumé> /// MainApp opstartsklasse for strukturelt /// Iterator Design Pattern. /// </summary> class MainApp { /// <summary> /// Indgangspunkt i konsolapplikationen. /// </summary> static void Main () { ConcreteAggregate a = new ConcreteAggregate (); a [ 0 ] = "Vare A" ; a [ 1 ] = "Vare B" ; a [ 2 ] = "Vare C" ; a [ 3 ] = "Vare D" ; // Opret Iterator og giv samlet ConcreteIterator i = ny ConcreteIterator ( a ); Konsol . WriteLine ( "Itererer over samling:" ); objektobjekt = i . _ først (); while (! i . IsDone ()) { Konsol . WriteLine ( item ); vare = i . næste (); } // Vent på brugerkonsollen . ReadKey (); } } /// <summary> /// Abstraktklassen 'Aggregate' /// </summary> abstrakt klasse Aggregate { public abstract Iterator CreateIterator (); public abstract int Count { get ; beskyttet sæt ; } public abstract object this [ int index ] { get ; sæt ; } } /// <summary> /// 'ConcreteAggregate'-klassen /// </summary> -klassen ConcreteAggregate : Aggregate { private readonly ArrayList _items = new ArrayList (); public override Iterator CreateIterator () { return new ConcreteIterator ( this ); } // Får vareantal public override int Antal { get { return _items . tælle ; } beskyttet sæt { } } // Indexer public override object this [ int index ] { get { return _items [ index ]; } sæt { _items . indsætte ( indeks , værdi ); } } } /// <summary> /// 'Iterator' abstrakt klasse /// </summary> abstrakt klasse Iterator { public abstract object First (); offentligt abstrakt objekt Næste (); offentlig abstrakt bool IsDone (); offentligt abstrakt objekt CurrentItem (); } /// <summary> /// 'ConcreteIterator'-klassen /// </summary> -klassen ConcreteIterator : Iterator { private readonly Aggregate _aggregate ; privat int _current ; // Constructor public ConcreteIterator ( Aggregeret aggregat ) { this . _aggregate = aggregat ; } // Henter første iterationselement public override object First () { return _aggregate [ 0 ]; } // Henter næste iterationselement public override object Next () { object ret = null ; _current ++; if ( _current < _aggregate . Count ) { ret = _aggregate [ _current ]; } returnere ret ; } // Henter aktuelt iterationselement public override object CurrentItem () { return _aggregate [ _current ]; } // Henter om iterationer er fuldstændige public override bool IsDone () { return _current >= _aggregate . tælle ; } } } Output Iteration over samling : Vare A Punkt B Punkt C Punkt D

PHP5

PHP5 kildekode /** * Iteratormønsteret giver en mekanisme til at iterere gennem elementerne i en samling uden at afsløre implementeringen af ​​samlingen. * * Iteration gennem elementerne udføres af iteratorobjektet, ikke af selve samlingen. * Dette forenkler grænsefladen og implementeringen af ​​samlingen og bidrager også til en mere logisk fordeling af ansvar. */ namespace iterator1 { /** * At have en fælles grænseflade er praktisk for klienten, fordi klienten er afkoblet fra implementeringen af ​​samlingen af ​​objekter. * * ConcreteAggregate indeholder en samling af objekter og implementerer en metode, der returnerer en iterator for denne samling. */ interface IAggregate { /** * Hver ConcreteAggregate-variant er ansvarlig for at skabe en Concrete Iterator-forekomst, som * kan bruges til at iterere over dens samling af objekter. */ offentlig funktion createIterator (); } /** * Iterator-grænsefladen skal implementeres af alle iteratorer. * * ConcreteIterator er ansvarlig for at administrere den aktuelle iterationsposition. */ interface IIterator { /** * @abstract * @return boolean er der et næste element i samlingen */ public function hasNext (); /** * @abstract * @return mixed next array element */ public function next (); /** * Fjerner det aktuelle element i samlingen * @abstract * @return void */ public function remove (); } /** * I mit eksempel bruger begge samlinger den samme iterator - en array-iterator. */ klasse ConcreteAggregate1 implementerer IAggregate { /** * @var Item[] $items */ public $items = array (); public function __construct () { $this -> items = array ( new Item ( 1 , 2 ), new Item ( 1 , 2 ), new Item ( 1 , 2 ), ); } public function createIterator () { return new ConcreteIterator1 ( $this -> items ); } } klasse ConcreteAggregate2 implementerer IAggregate { /** * @var Item[] $items */ public $items = array (); public function __construct () { $this -> items = array ( new Item ( 2 , 3 ), new Item ( 2 , 3 ), new Item ( 2 , 3 ), ); } public function createIterator () { return new ConcreteIterator1 ( $this -> items ); } } klasse ConcreteIterator1 implementerer IIterator { /** * @var Item[] $items */ protected $items = array (); /** * @var int $position gemmer den aktuelle iterationsposition i arrayet */ public $position = 0 ; /** * @param $items række af objekter, der skal itereres over */ public function __construct ( $items ) { $this -> items = $items ; } public function hasNext () { if ( $this -> position >= count ( $this -> items ) || count ( $this -> items ) == 0 ) { return ( false ); } else { return ( sand ); } } public function next () { $menuItem = $this -> items [ $this -> position ]; $this -> position ++ ; return ( $menuItem ); } public function remove () { if ( $this -> position <= 0 ) { throw new \Exception ( 'Du kan ikke kalde remove, før mindst en next() er blevet kaldt' ); } if ( $this -> items [ $this -> position - 1 ] != null ) { for ( $i = $this -> position - 1 ; $i < count ( $this -> items ); $i + + ) { $this -> items [ $i ] = $this -> items [ $i + 1 ]; } $this -> items [ count ( $this -> items ) - 1 ] = null ; } } } klasse Client { /** * @var ConcreteAggregate1 $aggregate1 */ public $aggregate1 ; /** * @var ConcreteAggregate2 $aggregate2 */ public $aggregate2 ; offentlig funktion __construct ( $aggregate1 , $aggregate2 ) { $this -> aggregate1 = $aggregate1 ; $this -> aggregat2 = $aggregate2 ; } public function printAggregatesItems () { $iterator1 = $this -> aggregate1 -> createIterator (); echo " \ nFirst" ; $this -> printIteratorItems ( $iterator1 ); $iterator2 = $this -> aggregate2 -> createIterator (); echo " \n\ nSecond" ; $this -> printIteratorItems ( $iterator2 ); } /** * @param $iterator IIterator */ privat funktion printIteratorItems ( $iterator ) { while ( $iterator -> hasNext ()) { $item = $iterator -> next (); echo " \n $item->navn $item->pris $item->beskrivelse " ; } } } klasse Vare { offentlig $pris ; offentlig $navn ; offentlig $beskrivelse ; offentlig funktion __construct ( $navn , $pris , $description = '' ) { $this -> name = $navn ; $this -> pris = $pris ; $this -> description = $beskrivelse ; } } $runner = ny klient ( ny ConcreteAggregate1 (), new ConcreteAggregate2 ()); $runner -> printAggregatesItems (); }

PHP5 builder iterator eksempel

PHP5 builder iterator kildekode /** * Komponistmønster med ekstern iterator * Iteratoren bruger rekursion til at iterere gennem træet af elementer */ navneområde compositeIterator { /** * Klienten bruger AComponent-grænsefladen til at arbejde med objekter. * AComponent-grænsefladen definerer grænsefladen for alle komponenter: både kombinationer og bladknuder. * AComponent kan implementere standardadfærd for add() remove() getChild() og andre operationer */ abstrakt klasse AComponent { offentlig $customPropertyName ; offentlig $customPropertyDescription ; /** * @param AComponent $component */ public function add ( $component ) { throw new \Exception ( "Ikke-understøttet operation" ); } /** * @param AComponent $component */ public function remove ( $component ) { throw new \Exception ( "Unsupported operation" ); } /** * @param int $int */ offentlig funktion getChild ( $int ) { throw new \Exception ( "Ikke-understøttet operation" ); } /** * @return IPhpLikeIterator */ abstrakt funktion createIterator (); public function operation1 () { throw new \Exception ( "Ikke-understøttet operation" ); } } /** * Leaf arver add() remove() getChild(-metoderne, hvilket måske ikke giver mening for en bladknude. * Selvom en bladknude kan betragtes som en node med nul børn * * Leaf definerer adfærden af ​​elementerne i en kombination. For at gøre dette implementerer den de operationer, der understøttes af Composite interface */ class Leaf udvider AComponent { public function __construct ( $name , $description = '' ) { $this -> customPropertyName = $name ; $this -> customPropertyDescription = $beskrivelse ; } offentlig funktion createIterator () { returner ny NullIterator (); } public function operation1 () { echo ( " \n Jeg er blad { $this -> customPropertyName } , jeg vil ikke udføre operation 1. { $this -> customPropertyDescription } " ); } } klasse NullIterator implementerer IPhpLikeIterator { public function valid () { return ( false ); } public function next () { return ( false ); } public function current () { return ( null ); } public function remove () { throw new \CException ( 'ikke-understøttet operation' ); } } /** * Den sammensatte grænseflade definerer adfærden for komponenter, der har børn, og giver lagerplads til dem. * * Composite implementerer også Leaf-specifikke operationer. Nogle af dem kan ikke undgå at give mening for kombinationer; i sådanne tilfælde kastes en undtagelse. */ klasse Composite udvider AComponent { privat $_iterator = null ; /** * @var \ArrayObject AComponent[] $komponenter til at gemme børn af typen AComponent */ public $components = null ; offentlig funktion __construct ( $navn , $description = '' ) { $this -> customPropertyName = $navn ; $this -> customPropertyDescription = $description ; } /** * @param AComponent $component */ public function add ( $component ) { if ( is_null ( $this -> komponenter )) { $this -> komponenter = new \ArrayObject ; } $dette -> komponenter -> tilføje ( $komponent ); } public function remove ( $component ) { foreach ( $this -> komponenter som $i => $c ) { if ( $c === $component ) { unset ( $this -> komponenter [ $i ]); } } } public function getChild ( $int ) { return ( $this -> komponenter [ $int ]); } public function operation1 () { echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; echo " \n --------------------------------" ; $iterator = $this -> komponenter -> getIterator (); while ( $iterator -> valid ()) { $component = $iterator -> current (); $komponent -> operation1 (); $iterator -> næste (); } } /** * @return CompositeIterator */ offentlig funktion createIterator () { if ( is_null ( $this -> _iterator )) { $this -> _iterator = new CompositeIterator ( $this -> komponenter -> getIterator ()); } return ( $this -> _iterator ); } } /** * Rekursiv sammensat iterator */ klasse CompositeIterator implementerer IPhpLikeIterator { public $stack = array (); /** * @param \ArrayIterator $componentsIterator */ offentlig funktion __construct ( $componentsIterator ) { //$this->stack= ny \ArrayObject; $this -> stak [] = $componentsIterator ; } public function remove () { throw new \CException ( 'ikke-understøttet operation' ); } public function valid () { if ( tom ( $this -> stack )) { return ( false ); } else { /** @var $componentsIterator \ArrayIterator */ // få det første element $componentsIterator = array_shift ( array_values ​​​​( $this -> stack )); if ( $componentsIterator -> gyldig ()) { return ( sand ); } else { array_shift ( $this -> stak ); return ( $this -> gyldig ()); } } } public function next () { /** @var $componentsIterator \ArrayIterator */ $componentsIterator = aktuel ( $this -> stack ); $component = $componentsIterator -> nuværende (); if ( $component instans af Composite ) { array_push ( $this -> stack , $component -> createIterator ()); } $componentsIterator -> næste (); //retur($komponent); } public function current () { if ( $this -> valid ()) { /** @var $componentsIterator \ArrayIterator */ // få det første element $componentsIterator = array_shift ( array_values ​( $this -> stack )) ; return ( $componentsIterator -> nuværende ()); } else { return ( null ); } } } /** * Iterator-grænsefladen skal implementeres af alle iteratorer. * Denne grænseflade er en del af standard php iterator-grænsefladen. * En bestemt iterator er ansvarlig for at administrere den aktuelle iterationsposition i en bestemt samling. */ interface IPhpLikeIterator { /** * @abstract * @return boolean er det aktuelle element */ public function valid (); /** * @abstract * @return blandet flyt markøren længere */ offentlig funktion næste (); /** * @abstract * @return blandet få det aktuelle element */ public function current (); /** * fjern det aktuelle element i samlingen * @abstract * @return void */ public function remove (); } class Client { /** * @varAComponent */ public $topItem ; offentlig funktion __construct ( $topItem ) { $this -> topItem = $topItem ; } offentlig funktion printOperation1 () { $this -> topItem -> operation1 (); } offentlig funktion printOperation2 () { echo " \n\n\n " ; $iterator = $this -> topItem -> createIterator (); while ( $iterator -> valid ()) { /** @var $component AComponent */ $component = $iterator -> current (); if ( strstr ( $component -> customPropertyName , 'leaf1' )) { echo ( " \n Jeg er klient, jeg fandt blad { $component -> customPropertyName } , lader jeg det bare stå her (for min 'første- leafs' tesamling). { $component -> customPropertyDescription } " ); } $iterator -> næste (); } } } klasse Test { public static function go () { $a = new Composite ( "c1" ); $b = ny sammensat ( "c2" ); $c = ny sammensat ( "c3" ); $topItem = new Composite ( "topelement" ); $topItem -> tilføje ( $a ); $topItem -> tilføje ( $b ); $topItem -> tilføje ( $c ); $a -> tilføje ( nyt blad ( "c1-blad1" )); $a -> add ( nyt blad ( "c1-blad2" )); $b -> tilføje ( nyt blad ( "c2-blad1" )); $b -> tilføje ( nyt blad ( "c2-blad2" )); $b -> tilføje ( nyt blad ( "c2-blad3" )); $c -> tilføje ( nyt blad ( "c3-blad1" )); $c -> tilføje ( nyt blad ( "c3-blad2" )); $client = ny klient ( $topItem ); $client -> printOperation1 (); $client -> printOperation2 (); } } test :: go (); }

Python

Kildekode i Python fra abc import ABCMeta , abstrakt metode klasse Iterator ( metaclass = ABCMeta ): """ Abstrakt iterator """ _error = Ingen # klassen for fejlen, der kastes, hvis samlingen er uden for grænserne def __init__ ( self , collection , cursor ): """ Konstruktør. :param-samling: samlingen, der skal gennemløbes af iteratoren :param-markør: startpositionen af ​​markøren i samlingen (tast) """ self ._collection = samling selv ._cursor = cursor @abstractmethod def current ( self ): """ Returner det aktuelle element, der peges på af iteratoren """ pass @abstractmethod def next ( self ): """ Flyt markøren til det næste element i samlingen og returner det """ pass @abstractmethod def has_next ( self ): """ Tjek om det næste element i samlingen eksisterer """ pass @abstractmethod def remove ( self ): """ Fjern det aktuelle element i samlingen, der peges på af markøren """ pass def _raise_key_exception ( self ): """ Hæv et ugyldigt indeks indeholdt i cursoren """ raise self . _error ( 'Samling af klasse {} har ikke nøglen " {} "' . format ( self . __class__ . __name__ , self . _cursor )) class ListIterator ( Iterator ): """ En iterator, der itererer over en normal liste """ _error = Indeksfejl def __init__ ( selv , samling : liste ): super () . __init__ ( samling , 0 ) def nuværende ( selv ): hvis selv . _cursor < len ( selv . _samling ): returnere selv . _samling [ selv . _cursor ] selv . _hæve_nøgle_undtagelse () def næste ( selv ): hvis len ( selv . _samling ) >= selv . _cursor + 1 : selv . _cursor += 1 returnerer selv . _samling [ selv . _cursor ] selv . _hæve_nøgle_undtagelse () def has_next ( selv ): returner len ( self . _collection ) >= self . _cursor + 1 def fjern ( selv ): hvis 0 <= selv . _cursor < len ( selv . _samling ): selv . _samling . fjerne ( selv . _samling [ selv._cursor ] ) andet : selv . _ _hæve_nøgle_undtagelse () klasse DictIterator ( Iterator ): """ Ordbogsiterator - på grund af det faktum, at ordbøger i Python er implementeret som hashtabeller, kan gennemløbsrækkefølgen ændre sig under forskellige kørsler """ _error = KeyError def __init__ ( selv , samling : dict ): super () . __init__ ( samling , næste ( iter ( samling ))) selv . _keys = liste ( self . _collection . keys ()) self . _nøgler . pop ( 0 ) def nuværende ( selv ): hvis selv . _cursor i sig selv . _kollektion : returner selv . _samling [ selv . _cursor ] selv . _hæve_nøgle_undtagelse () def næste ( selv ): hvis len ( selv . _nøgler ): selv . _cursor = selv . _nøgler . pop ( 0 ) returnere selv . _samling [ selv . _cursor ] andet : selv . _hæve_nøgle_undtagelse () def has_next ( self ): returner len ( self . _keys ) > 0 def fjerne ( selv ): hvis selv . _cursor i sig selv . _samling : del selv . _samling [ selv . _cursor ] prøv : selv . næste () undtagen selv . _error : raise KeyError ( 'Samling af typen {} er tom' . format ( self . __class__ . __name__ )) andet : self . _hæve_nøgle_undtagelse () klassesamling ( metaklasse = ABCMeta ) : """ Abstrakt samling """ @abstractmethod def iterator ( selv ): bestå klasse ListCollection ( Collection ): """ En indpakningssamling til en normal liste """ def __init__ ( selv , samling : liste ): selv . _samling = samling def iterator ( selv ): returner ListIterator ( self . _collection ) klasse DictCollection ( Samling ): """ Indpakningssamling til ordbog """ def __init__ ( selv , samling : dikt ): selv . _samling = samling def iterator ( selv ): returner DictIterator ( selv . _kollektion ) def test ( title = str , collection = Collection ): print ( " \n {} \n " . format ( title )) iterator = samling . iterator () print ( iterator . aktuelle ()) iterator . næste () print ( iterator . næste ()) iterator . fjern () print ( iterator . aktuelle ()) print ( iterator . has_next ()) print () if __name__ == '__main__' : print ( 'OUTPUT:' ) test ( 'List testing' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ])) test ( 'Ordbogstest' , DictCollection ({ 'a') : 1 , 'b' : 2 , 'c' : 3 , 'f' : 8 })) ''' OUTPUT: Liste test 1 3 4 Sandt Ordbogstest 1 3 2 Falsk '''

Rust

Rust eksempel #[aflede(Debug, Clone, Copy)] pub struct EksempelRange { begynde : i64 , nuværende : i64 , slut : i64 , } impl Eksempelområde { pub fn new ( begyndelse : i64 , slut : i64 ) -> Selv { Eksempelområde { begynde , nuværende : begynde , ende , } } pub fn iter ( & self ) -> Eksempelområde { * selv } } brug std :: fmt ; impl fmt :: Display for ExampleRange { fn fmt ( & self , f : & mut fmt :: Formatter <' _ > ) -> fmt :: Resultat { skrive! ( f , " {} " , selv . aktuel ) } } impl Iterator for ExampleRange { typeItem = i64 ; _ fn næste ( & mut self ) -> Mulighed < Self :: Item > { hvis selv . nuværende < selv . ende { ( Nogle ( selv . strøm ), selv . strøm += 1 ). 0 } andet { Ingen } } fn last ( mut self ) -> Mulighed < Self :: Item > { hvis selv . nuværende > selv . begynde { ( selv . strøm -= 1 , Nogle ( selv . strøm )). en } andet { Ingen } } } fn main () { lad det = Eksempelområde :: new ( 0 , 6 ); for varen i den { println! ( "{}" , element ); } } ''' OUTPUT : 0 en 2 3 fire 5 '''