Iteraattori (suunnittelukuvio)

Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 9. toukokuuta 2016 tarkistetusta versiosta . tarkastukset vaativat 9 muokkausta .
iteraattori
Iteraattori
Tyyppi käyttäytymiseen
Kuvattu suunnittelukuvioissa Joo

Iteraattori  on käyttäytymissuunnittelumalli . _ Edustaa objektia, joka mahdollistaa peräkkäisen pääsyn koosteobjektin elementteihin käyttämättä kunkin koosteobjektin kuvauksia .

Esimerkiksi elementit, kuten puu , linkitetty luettelo , hash-taulukko ja taulukko , voidaan kulkea (ja muokata) Iterator -objektin avulla .

Elementtien iteroinnin suorittaa iteraattoriobjekti, ei itse kokoelma. Tämä yksinkertaistaa käyttöliittymää ja kokoelman toteutusta sekä edistää huolenaiheiden loogisempaa erottelua .

Täysin toteutetun iteraattorin ominaisuus on, että iteraattoria käyttävä koodi ei välttämättä tiedä mitään iteroidun aggregaatin tyypistä.

Tietenkin (C++:ssa) melkein mikä tahansa aggregaatti voidaan iteroida void*-osoittimella, mutta:

Iteraattorit antavat sinun abstraktoida aggregaatin tyypin ja päätteen käyttämällä polymorfista Next-komentoa (joka on usein toteutettu operaattorina++ C++:ssa) ja polymorfista aggregate.end(), joka palauttaa "aggregaatin lopun".

Siten on mahdollista työskennellä iteraattorien alueiden kanssa, jos iteroidun aggregaatin tyypistä ei ole tietoa. Esimerkiksi:

Iteraattori itBegin = aggregate . alkaa (); Iteraattori itEnd = aggregaatti . loppu (); func ( itBegin , itEnd );

Ja kauemmas:

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

Esimerkkejä

C#

Lähdeteksti C# /* esimerkkikoodi C#:ssa Tämä rakennekoodi esittelee Iterator-mallin, joka tarjoaa tavan kulkea (iteroida) esinekokoelman yli ilman kokoelman taustalla olevaa rakennetta. */ piilota koodi // Iteraattorimalli -- Rakenneesimerkki käyttäen System ; käyttämällä System.Collections -ohjelmaa ; nimiavaruus DoFactory.GangOfFour.Iterator.Structural { /// <summary> /// MainApp-käynnistysluokka Structuralille /// Iterator Design Pattern. /// </summary> luokka MainApp { /// <summary> /// Pääsypiste konsolisovellukseen. /// </summary> static void Main () { ConcreteAggregate a = new ConcreteAggregate (); a [ 0 ] = "Kohde A" ; a [ 1 ] = "Kohde B" ; a [ 2 ] = "Kohde C" ; a [ 3 ] = "Kohde D" ; // Luo iteraattori ja anna aggregaatti ConcreteIterator i = uusi ConcreteIterator ( a ); konsoli . WriteLine ( "Iteroidaan kokoelman yli:" ); objektikohde = i . _ ensimmäinen (); while (! i . IsDone ()) { Konsoli . WriteLine ( kohde ); kohde = i . seuraava (); } // Odota käyttäjän konsolia . ReadKey (); } } /// <summary> /// 'Aggregate' abstrakti luokka /// </summary> abstract class Aggregate { public abstract Iterator CreateIterator (); julkinen abstrakti int Count { get ; suojattu sarja ; } julkinen abstrakti objekti this [ int index ] { get ; asettaa ; } } /// <summary> /// 'ConcreteAggregate'-luokka /// </summary> class ConcreteAggregate : Aggregate { private readonly ArrayList _items = new ArrayList (); public override Iterator CreateIterator () { return new ConcreteIterator ( this ); } // Hakee nimikkeiden määrän public override int Count { get { return _items . laskea ; } suojattu joukko { } } // Indeksoijan julkinen ohitusobjekti this [ int index ] { get { return _items [ index ] ; } asettaa { _kohteita . insert ( indeksi , arvo ); } } } /// <summary> /// 'Iteraattori' abstrakti luokka /// </summary> abstrakti luokka Iteraattori { julkinen abstrakti objekti Ensimmäinen (); julkinen abstrakti objekti Seuraava (); julkinen abstrakti bool IsDone (); julkinen abstrakti objekti CurrentItem (); } /// <summary> /// 'ConcreteIterator'-luokka /// </summary> class ConcreteIterator : Iteraattori { private readonly Aggregate _aggregate ; yksityinen int _current ; // Rakentaja public ConcreteIterator ( Aggregate aggregate ) { this . _aggregate = aggregaatti ; } // Hakee ensimmäisen iterointikohteen public override object First () { return _aggregate [ 0 ]; } // Hakee seuraavan iterointikohteen public override object Next () { object ret = null ; _current ++; if ( _nykyinen < _aggregate . Count ) { ret = _aggregate [ _current ]; } paluu ret ; } // Hakee nykyisen iterointikohteen julkisen ohitusobjektin CurrentItem () { return _aggregate [ _current ] ; } // Hakee, ovatko iteraatiot täydellisiä julkisen ohituksen bool IsDone () { return _current >= _aggregate . laskea ; } } } Tuotos Iteroi kokoelman päälle : Nimike A Nimike B Kohde C Tuote D

PHP5

PHP5 lähdekoodi /** * Iteraattorimalli tarjoaa mekanismin, jolla iteroidaan kokoelman elementtejä paljastamatta kokoelman toteutusta. * * Iteroinnin elementtien läpi suorittaa iteraattoriobjekti, ei itse kokoelma. * Tämä yksinkertaistaa käyttöliittymää ja kokoelman toteutusta ja edistää myös loogisempaa vastuunjakoa. */ namespace iterator1 { /** * Yhteinen käyttöliittymä on kätevä asiakkaalle, koska asiakas on irrotettu objektikokoelman toteutuksesta. * * ConcreteAggregate sisältää kokoelman objekteja ja toteuttaa menetelmän, joka palauttaa iteraattorin tälle kokoelmalle. */ interface IAggregate { /** * Jokainen ConcreteAggregate-maku on vastuussa Concrete Iterator -esiintymän luomisesta, jota * voidaan käyttää iteroitaessa sen objektikokoelmaa. */ julkinen toiminto createIterator (); } /** * Kaikkien iteraattorien on otettava käyttöön Iterator-liitäntä. * * ConcreteIterator on vastuussa nykyisen iterointipaikan hallinnasta. */ interface IIterator { /** * @abstract * @return boolean onko kokoelmassa seuraava elementti */ public function hasNext (); /** * @abstract * @return sekoitettu seuraava taulukkoelementti */ public function next (); /** * Poistaa kokoelman nykyisen elementin * @abstract * @return void */ julkinen toiminto poista (); } /** * Esimerkissäni molemmat kokoelmat käyttävät samaa iteraattoria - taulukkoiteraattoria. */ luokka ConcreteAggregate1 toteuttaa IAggregaten { /** * @var Item[] $kohteet */ julkinen $kohteet = 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 ); } } luokka ConcreteAggregate2 toteuttaa IAggregate:n { /** * @var Item[] $kohteet */ julkinen $kohteet = 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 ); } } class ConcreteIterator1 toteuttaa IIteratorin { /** * @var Item[] $kohteet */ suojattu $kohteet = array (); /** * @var int $sijainti tallentaa nykyisen iteraatiopaikan taulukossa */ julkinen $sijainti = 0 ; /** * @param $items toistettavien objektien joukko */ julkinen toiminto __construct ( $items ) { $this -> items = $items ; } public function hasNext () { if ( $this -> position >= count ( $this -> items ) || count ( $this -> items ) == 0 ) { return ( false ); } else { return ( true ); } } public function next () { $menuItem = $this -> items [ $this -> position ]; $this -> sijainti ++ ; paluu ( $menuItem ); } public function remove () { if ( $this -> position <= 0 ) { throw new \Exception ( 'Et voi kutsua remove ennen kuin ainakin yksi next() on kutsuttu' ); } 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 ; } } } class Client { /** * @var ConcreteAggregate1 $aggregate1 */ julkinen $aggregate1 ; /** * @var ConcreteAggregate2 $aggregate2 */ julkinen $aggregate2 ; julkinen funktio __konstrukti ( $aggregate1 , $aggregate2 ) { $this -> aggregate1 = $aggregate1 ; $this -> aggregate2 = $aggregate2 ; } public function printAggregatesItems () { $ iterator1 = $this -> aggregate1 -> createIterator (); echo " \ nEnsin" ; $this -> printIteratorItems ( $ iterator1 ); $iteraattori2 = $this -> aggregate2 -> createIterator (); echo " \n\ nSekunti" ; $this -> printIteratorItems ( $ iterator2 ); } /** * @param $iterator IIterator */ yksityinen toiminto printIteratorItems ( $ iterator ) { while ( $ iterator -> hasNext ()) { $ iterator = $iterator -> next (); echo " \n $tuote->nimi $tuote->hinta $tuote->kuvaus " ; } } } class Tuote { julkinen $hinta ; julkinen $nimi ; julkinen $description ; julkinen funktio __konstrukti ( $nimi , $hinta , $kuvaus = '' ) { $this -> name = $nimi ; $tämä -> hinta = $hinta ; $this -> kuvaus = $kuvaus ; } } $runner = uusi asiakas ( uusi ConcreteAggregate1 (), uusi ConcreteAggregate2 ()); $runner -> printAggregatesItems (); }

PHP5 Builder iterator esimerkki

PHP5 builder iterator lähdekoodi /** * Säveltäjäkuvio ulkoisella iteraattorilla * Iteraattori käyttää rekursiota iteroidakseen elementtipuun läpi */ namespace compositeIterator { /** * Asiakas käyttää AComponent-käyttöliittymää objektien kanssa työskentelyyn. * AComponent-liitäntä määrittää käyttöliittymän kaikille komponenteille: sekä yhdistelmille että lehtisolmuille. * AComponent voi toteuttaa oletuskäyttäytymisen add() remove() getChild()- ja muille operaatioille */ abstrakti luokka AComponent { julkinen $customPropertyName ; julkinen $customPropertyDescription ; /** * @param AComponent $komponentti */ public function add ( $komponentti ) { throw new \Exception ( "Ei tuettu toiminto" ); } /** * @param AComponent $komponentti */ julkinen toiminto poista ( $komponentti ) { throw new \Exception ( "Toiminta ei tueta" ); } /** * @param int $int */ public function getChild ( $int ) { throw new \Exception ( "Toiminta ei tueta" ); } /** * @return IPhpLikeIterator */ abstrakti funktio createIterator (); public function operation1 () { throw new \Exception ( "Ei tuettu toiminto" ); } } /** * Leaf perii add() remove() getChild(-menetelmät, mikä ei ehkä ole järkevää lehtisolmulle. * Vaikka lehtisolmua voidaan pitää solmuna, jolla ei ole lapsia * * Leaf määrittelee elementtien käyttäytymisen Tätä varten se toteuttaa Composite interfacen tukemat toiminnot */ luokka Leaf extends AComponent { public function __construct ( $nimi , $description = '' ) { $this -> customPropertyName = $nimi ; $this -> customPropertyDescription = $kuvaus ; } public function createIterator () { return new NullIterator (); } public function operation1 () { echo ( " \n Olen lehti { $this -> customPropertyName } , en halua tehdä toimintoa 1. { $this -> customPropertyDescription } " ); } } luokka NullIterator toteuttaa IPhpLikeIterator { public function valid () { return ( false ); } public function next () { return ( false ); } julkinen funktio nykyinen () { return ( null ); } public function remove () { heittä uusi \CEexception ( 'ei tuettu toiminto' ); } } /** * Komposiittirajapinta määrittää niiden komponenttien toiminnan, joilla on lapsia, ja tarjoaa niille tallennustilan. * * Composite toteuttaa myös Leaf-kohtaisia ​​toimintoja. Jotkut niistä eivät voi olla järkeviä yhdistelmille; tällaisissa tapauksissa tehdään poikkeus. */ luokka Komposiitti laajentaa AComponent { yksityinen $_iterator = null ; /** * @var \ArrayObject AComponent[] $komponentit AComponent-tyypin lapsien tallentamiseen */ public $komponentit = null ; public function __construct ( $nimi , $description = '' ) { $this -> customPropertyName = $nimi ; $this -> customPropertyDescription = $description ; } /** * @param AComponent $komponentti */ julkinen funktio add ( $komponentti ) { if ( is_null ( $this -> komponentit )) { $this -> komponentit = new \ArrayObject ; } $this -> komponentit -> append ( $komponentti ); } public function poista ( $komponentti ) { foreach ( $this -> komponentit kuten $i => $c ) { if ( $c === $komponentti ) { unset ( $this -> komponentit [ $i ]); } } } public function getChild ( $int ) { return ( $this -> komponentit [ $int ]); } public function operation1 () { echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; echo " \n --------------------------------" ; $iterator = $this -> komponentit -> getIterator (); while ( $iteraattori -> voimassa ()) { $komponentti = $iteraattori -> nykyinen (); $komponentti -> operaatio1 (); $iteraattori -> seuraava (); } } /** * @return CompositeIterator */ julkinen toiminto createIterator () { if ( on_null ( $this -> _iterator )) { $this -> _iterator = new CompositeIterator ( $this -> komponentit -> getIterator ()); } return ( $this -> _iterator ); } } /** * Rekursiivinen komposiittiiteraattori */ luokka CompositeIterator toteuttaa IPhpLikeIterator { julkinen $pino = array (); /** * @param \ArrayIterator $componentsIterator */ julkinen funktio __construct ( $componentsIterator ) { //$this->stack= new \ArrayObject; $this -> pino [] = $componentsIterator ; } public function remove () { heittä uusi \CEexception ( 'ei tuettu toiminto' ); } public function valid () { if ( tyhjä ( $this -> pino )) { return ( false ); } else { /** @var $componentsIterator \ArrayIterator */ // hanki ensimmäinen elementti $componentsIterator = array_shift ( array_values ​​​​( $this -> pino )); if ( $componentsIterator -> valid ()) { return ( true ); } else { array_shift ( $this -> pino ); return ( $this -> valid ()); } } } public function next () { /** @var $componentsIterator \ArrayIterator */ $componentsIterator = nykyinen ( $this -> pino ); $komponentti = $komponentitIterator -> nykyinen (); if ( $komponentin esiintymä komposiitti ) { array_push ( $this -> pino , $komponentti -> createIterator ()); } $componentsIterator -> seuraava (); //return($komponentti); } public function current () { if ( $this -> valid ()) { /** @var $componentsIterator \ArrayIterator */ // hanki ensimmäinen elementti $componentsIterator = array_shift ( array_values ​​​​( $this -> pino )) ; return ( $componentsIterator -> nykyinen ()); } else { return ( null ); } } } /** * Kaikkien iteraattorien on otettava käyttöön Iterator-liitäntä. * Tämä käyttöliittymä on osa tavallista php iterator -liitäntää. * Tietty iteraattori on vastuussa nykyisen iterointipaikan hallinnasta tietyssä kokoelmassa. */ käyttöliittymä IPhpLikeIterator { /** * @abstract * @return boolean on nykyinen elementti */ julkinen funktio kelvollinen (); /** * @abstract * @return sekoitettu siirrä kursoria edelleen */ julkinen toiminto seuraava (); /** * @abstract * @return sekoitettu saada nykyinen elementti */ public function current (); /** * poista kokoelman nykyinen elementti * @abstract * @return void */ julkinen toiminto poista (); } class Client { /** * @varAComponent */ public $topItem ; public function __construct ( $topItem ) { $this -> topItem = $topItem ; } public function printOperation1 () { $this -> topItem -> operation1 (); } public function printOperation2 () { echo " \n\n\n " ; $ iterator = $this -> topItem -> createIterator (); while ( $iteraattori -> kelvollinen ()) { /** @var $komponentti AComponent */ $komponentti = $iteraattori -> nykyinen (); if ( strstr ( $komponentti -> customPropertyName , 'leaf1' )) { echo ( " \n Olen asiakas, löysin leaf { $komponentti -> customPropertyName } , jätän sen tähän (ensimmäisenä lehtien teekokoelma). { $komponentti -> customPropertyDescription } " ); } $iteraattori -> seuraava (); } } } class Test { julkinen staattinen funktio go () { $a = uusi Yhdistelmä ( "c1" ); $b = uusi komposiitti ( "c2" ); $c = uusi komposiitti ( "c3" ); $topItem = uusi komposiitti ( "top item" ); $topItem -> lisää ( $a ); $topItem -> lisää ( $b ); $topItem -> lisää ( $c ); $a -> add ( new Leaf ( "c1-leaf1" )); $a -> add ( new Leaf ( "c1-leaf2" )); $b -> add ( new Leaf ( "c2-leaf1" )); $b -> add ( new Leaf ( "c2-leaf2" )); $b -> add ( new Leaf ( "c2-leaf3" )); $c -> add ( new Leaf ( "c3-leaf1" )); $c -> add ( new Leaf ( "c3-leaf2" )); $asiakas = uusi asiakas ( $topItem ); $asiakas -> tulostustoiminto1 (); $client -> printOperation2 (); } } testi :: mene (); }

Python

Lähdekoodi Pythonissa abc importista ABCMeta , abstrakti menetelmä luokan iteraattori ( metaluokka = ABCMeta ): """ Abstrakti iteraattori """ _error = Ei mitään # virheluokka, joka syntyy, jos kokoelma on rajojen ulkopuolella def __init__ ( itse , kokoelma , kohdistin ): """ Rakentaja. :param-kokoelma: iteraattorin läpi kulkeva kokoelma : param cursor: kursorin alkusijainti kokoelmassa (avain) """ self ._collection = kokoelma itse ._cursor = kohdistin @abstractmethod def current ( self ): """ Palauttaa nykyisen elementin, johon iteraattorin """ passi osoittaa @abstractmethod def next ( self ): """ Siirrä kohdistin kokoelman seuraavaan elementtiin ja palauta se """ pass @abstractmethod def has_next ( self ): """ Tarkista, onko kokoelman seuraava elementti olemassa """ pass @abstractmethod def remove ( self ): """ Poista kokoelman nykyinen elementti, johon kohdistimen """ kulku osoittaa def _raise_key_exception ( self ): """ Nosta kohdistimen sisältämä virheellinen indeksi "" nosta itse . _error ( 'Luokan {} kokoelmalla ei ole avainta " {} "' . muoto ( itse . __class__ . __name__ , itse . _kursori )) luokan ListIterator ( Iteraattori ): """ Iteraattori , joka iteroi normaalin luettelon """ yli _error = IndexError def __init__ ( itse , kokoelma : lista ): super () . __init__ ( kokoelma , 0 ) def virta ( itse ): jos itse . _kursori < len ( itse . _kokoelma ): palauta itse . _kokoelma [ itse . _kursori ] itse . _raise_key_exception () def next ( itse ): if len ( itse . _kokoelma ) >= itse . _kursori + 1 : itse . _cursor += 1 palauttaa itsensä . _kokoelma [ itse . _kursori ] itse . _raise_key_exception () def has_next ( self ): return len ( self . _collection ) >= self . _kursori + 1 def poista ( itse ): jos 0 <= itse . _kursori < len ( itse . _kokoelma ): itse . _kokoelma . poista ( itse . _kokoelma [ itse . _kursori ] ) else : itse . _raise_key_exception () luokan DictIterator ( Iterator ): """ Sanakirjaiteraattori - koska Pythonissa sanakirjat on toteutettu hash-taulukoina, läpikulkujärjestys voi muuttua eri ajon aikana """ _error = KeyError def __init__ ( itse , kokoelma : dict ): super () . __init__ ( kokoelma , next ( iter ( kokoelma ))) itse . _keys = lista ( itse . _kokoelma . avaimet ()) itse . _avaimet . pop ( 0 ) def virta ( itse ): jos itse . _kursori itsessään . _ _collection : palauta itsesi . _kokoelma [ itse . _kursori ] itse . _raise_key_exception () def next ( self ): if len ( self . _keys ): itse . _kursori = itse . _avaimet . pop ( 0 ) palaa itse . _kokoelma [ itse . _cursor ] else : itse . _raise_key_exception () def has_next ( self ): return len ( self . _keys ) > 0 def poista ( itse ): jos itse . _kursori itsessään . _ _collection : del self . _kokoelma [ itse . _cursor ] try : self . seuraava () paitsi itse . _error : nosta KeyError ( 'Tyypin {} kokoelma on tyhjä' . muoto ( self . __class__ . __name__ )) else : self . _raise_key_exception () luokan kokoelma ( metaclass = ABCMeta ): """ Abstrakti kokoelma """ @abstractmethod def iterator ( itse ): hyväksytty luokka ListCollection ( Kokoelma ): """ Normaalin luettelon """ käärekokoelma def __init__ ( itse , kokoelma : lista ): itse . _collection = kokoelma def iterator ( itse ): palauttaa ListIterator ( itse . _collection ) luokka DictCollection ( Kokoelma ): """ Käärekokoelma sanakirjalle "" def __init__ ( itse , kokoelma : dict ): itse . _collection = kokoelma def iterator ( itse ): return DictIterator ( itse . _collection ) def testi ( otsikko = str , kokoelma = Kokoelma ): tulosta ( " \n {} \n " . muoto ( otsikko ) ) iterator = kokoelma . iteraattori () tulosta ( iteraattori . nykyinen ()) iteraattori . seuraava () tulosta ( iteraattori . seuraava ()) iteraattori . poista () tulosta ( iteraattori . nykyinen ()) tulosta ( iteraattori . has_next ()) tulosta () if __name__ == '__main__' : print ( 'OUTPUT:' ) testi ( 'Listan testaus' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ])) testi ( 'Sanakirjan testaus' , DictCollection ({ 'a') : 1 , 'b' : 2 , 'c' : 3 , 'f' : 8 })) ''' TULOSTUS: Listan testaus 1 3 4 Totta Sanakirjan testaus 1 3 2 False ''

Ruoste

Esimerkki ruosteesta #[johdella (debug, kloonaa, kopioi)] pub - rakenne EsimerkkiRange { alkaa : i64 , nykyinen : i64 , loppu : i64 , } impl EsimerkkiRange { pub fn uusi ( alku : i64 , loppu : i64 ) -> itse { Esimerkkialue { alkaa , nykyinen : alkaa , loppu , } } pub fn iter ( & self ) -> Esimerkkialue { * itse } } käytä std :: fmt ; impl fmt :: Esimerkkialueen näyttö _ { fn fmt ( & self , f : & mut fmt :: Muotoilu <' _ > ) -> fmt :: Tulos { kirjoittaa! ( f , "{}" , itse . nykyinen ) } } Impl Iteraattori esimerkkialueelle _ { typeItem = i64 ; _ fn seuraava ( & mut self ) -> Vaihtoehto < Itse :: Kohde > { jos itse . nykyinen < itse . loppu { ( Jotkut ( itse . virta ), itse . virta += 1 ). 0 } muu { Ei mitään } } fn last ( mut self ) -> Optio < Self :: Item > { jos itse . nykyinen > itse . alkaa { ( itse . virta -= 1 , Jotkut ( itse . virta )). yksi } muu { Ei mitään } } } fn main () { anna sen = Esimerkkialue :: uusi ( 0 , 6 ); siinä olevalle kohteelle _ { println! ( "{}" , kohde ); } } '''' TULO : 0 yksi 2 3 neljä 5 ''''