Iterátor (návrhový vzor)

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 9. května 2016; kontroly vyžadují 9 úprav .
iterátor
Iterátor
Typ behaviorální
Popsáno v Návrhové vzory Ano

Iterátor  je behaviorální návrhový vzor . Představuje objekt, který umožňuje sekvenční přístup k prvkům agregovaného objektu bez použití popisů každého z agregovaných objektů.

Například prvky jako strom , propojený seznam , hashovací tabulka a pole lze procházet (a upravovat) pomocí objektu Iterator .

Iteraci mezi prvky provádí objekt iterátoru, nikoli samotná kolekce. To zjednodušuje rozhraní a implementaci kolekce a podporuje logičtější oddělení zájmů .

Funkce plně implementovaného iterátoru spočívá v tom, že kód, který používá iterátor, nemusí vědět nic o typu iterovaného agregátu.

Samozřejmě (v C++) lze téměř jakýkoli agregát iterovat s ukazatelem void*, ale:

Iterátory vám umožňují abstrahovat typ a terminátor agregátu pomocí polymorfního Next (často implementovaného jako operátor++ v C++) a polymorfního agregátu.end(), který vrací „end of agregát“.

Díky tomu je možné pracovat s rozsahy iterátorů při absenci znalostí o typu iterovaného agregátu. Například:

Iterátor itBegin = agregace . začít (); Iterátor itEnd = agregace . konec (); func ( itBegin , itEnd );

A dál:

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

Příklady

C#

Zdrojový text v C# /* ukázkový kód v C# Tento strukturální kód demonstruje vzor iterátoru, který poskytuje způsob, jak procházet (iterovat) sbírkou položek, aniž by se podrobně popisovala základní struktura kolekce. */ skrýt kód // Vzor iterátoru -- Příklad struktury pomocí System ; pomocí System.Collections ; jmenný prostor DoFactory.GangOfFour.Iterator.Structural { /// <summary> /// Spouštěcí třída MainApp pro Structural /// Vzor návrhu iterátoru. /// </summary> class MainApp { /// <summary> /// Vstupní bod do konzolové aplikace. /// </summary> static void Main () { ConcreteAggregate a = new ConcreteAggregate (); a [ 0 ] = "Položka A" ; a [ 1 ] = "Položka B" ; a [ 2 ] = "Položka C" ; a [ 3 ] = "Položka D" ; // Vytvoří Iterator a poskytne souhrnný ConcreteIterator i = new ConcreteIterator ( a ); Konzole . WriteLine ( "Iterace přes kolekci:" ); předmětová položka = i . první (); while (! i . IsDone ()) { Console . WriteLine ( položka ); položka = i . další (); } // Počkejte na uživatelskou konzoli . ReadKey (); } } /// <summary> /// Abstraktní třída 'Aggregate' /// </summary> abstract class Aggregate { public abstract Iterator CreateIterator (); public abstract int Count { get ; chráněná sada ; } public abstract object this [ int index ] { get ; nastavit ; } } /// <summary> /// Třída 'ConcreteAggregate' /// </summary> class ConcreteAggregate : Aggregate { private readonly ArrayList _items = new ArrayList (); public override Iterator CreateIterator () { return new ConcreteIterator ( this ); } // Získá počet položek public override int Count { get { return _items . počítat ; } chráněná sada { } } // Indexer public override object this [ int index ] { get { return _items [ index ]; } set { _items . vložit ( index , hodnota ); } } } /// <summary> /// Abstraktní třída 'Iterátor' /// </summary> abstract class Iterator { public abstract object First (); veřejný abstraktní objekt Další (); public abstract bool IsDone (); veřejný abstraktní objekt CurrentItem (); } /// <summary> /// Třída 'ConcreteIterator' /// </summary> class ConcreteIterator : Iterator { private readonly Aggregate _aggregate ; private int _current ; // Konstruktor public ConcreteIterator ( Agregátní agregát ) { this . _aggregate = agregovat ; } // Získá první položku iterace public override object First () { return _aggregate [ 0 ]; } // Získá další položku iterace public override object Next () { object ret = null ; _aktuální ++; if ( _current < _aggregate . Count ) { ret = _aggregate [ _current ]; } vrátit ret ; } // Získá aktuální položku iterace public override object CurrentItem () { return _aggregate [ _current ]; } // Vrátí, zda jsou iterace kompletní public override bool IsDone () { return _current >= _aggregate . počítat ; } } } Výstup Iterace přes kolekci : Položka A Položka B Položka C Položka D

PHP5

Zdrojový kód PHP5 /** * Vzor iterátoru poskytuje mechanismus pro iteraci prvků kolekce bez odhalení implementace kolekce. * * Iteraci mezi prvky provádí objekt iterátoru, nikoli samotná kolekce. * To zjednodušuje rozhraní a implementaci kolekce a také přispívá k logičtějšímu rozdělení odpovědností. */ jmenný prostor iterator1 { /** * Společné rozhraní je pro klienta výhodné, protože klient je oddělen od implementace kolekce objektů. * * ConcreteAggregate obsahuje kolekci objektů a implementuje metodu, která vrací iterátor pro tuto kolekci. */ interface IAggregate { /** * Každá varianta ConcreteAggregate je zodpovědná za vytvoření instance Concrete Iterator, kterou * lze použít k iteraci přes její kolekci objektů. */ public function createIterator (); } /** * Rozhraní iterátoru musí být implementováno všemi iterátory. * * ConcreteIterator je zodpovědný za správu aktuální pozice iterace. */ interface IIterator { /** * @abstract * @return boolean je zde další prvek v kolekci */ public function hasNext (); /** * @abstract * @return smíšený další prvek pole */ public function next (); /** * Odebere aktuální prvek kolekce * @abstract * @return void */ public function remove (); } /** * V mém příkladu obě kolekce používají stejný iterátor - iterátor pole. */ class ConcreteAggregate1 implementuje 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 ); } } class ConcreteAggregate2 implementuje 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 ); } } class ConcreteIterator1 implementuje IIterator { /** * @var Item[] $items */ protected $items = array (); /** * @var int $position ukládá aktuální pozici iterace do pole */ public $position = 0 ; /** * @param $items pole objektů k iteraci */ public function __construct ( $items ) { $this -> items = $items ; } public function hasNext () { if ( $this -> pozice >= count ( $this -> items ) || count ( $this -> items ) == 0 ) { return ( false ); } else { return ( true ); } } public function next () { $menuItem = $this -> položky [ $this -> pozice ]; $this -> pozice ++ ; return ( $menuItem ); } public function remove () { if ( $this -> pozice <= 0 ) { throw new \Exception ( 'Nemůžete volat remove, dokud nebude zavolána alespoň jedna next()' ); } if ( $this -> položky [ $this -> pozice - 1 ] != null ) { for ( $i = $this -> pozice - 1 ; $i < počet ( $this -> položky ); $i + + ) { $this -> položky [ $i ] = $this -> položky [ $i + 1 ]; } $this -> položky [ počet ( $this -> položky ) - 1 ] = null ; } } } class Klient { /** * @var ConcreteAggregate1 $aggregate1 */ public $aggregate1 ; /** * @var ConcreteAggregate2 $aggregate2 */ public $aggregate2 ; public function __construct ( $aggregate1 , $aggregate2 ) { $this -> agregát1 = $aggregate1 ; $this -> agregát2 = $agregát2 ; } public function printAggregatesItems () { $iterator1 = $this - > agregát1 -> createIterator (); echo " \ nPrvní" ; $this -> printIteratorItems ( $iterator1 ); $iterator2 = $this - > agregát2 -> createIterator (); echo " \n\ nDruhá" ; $this -> printIteratorItems ( $iterator2 ); } /** * @param $iterator IIterator */ private function printIteratorItems ( $iterator ) { while ( $iterator -> hasNext ()) { $item = $iterator -> dalsi (); echo " \n $položka->název $položka->cena $položka->popis " ; } } } class Item { public $cena ; veřejné $jméno ; veřejný $popis ; public function __construct ( $name , $cena , $description = '' ) { $this -> name = $name ; $toto -> cena = $cena ; $toto -> popis = $popis ; } } $runner = nový klient ( new ConcreteAggregate1 (), new ConcreteAggregate2 ()); $runner -> printAggregatesItems (); }

Příklad iterátoru PHP5 builderu

Zdrojový kód iterátoru PHP5 builderu /** * Vzor skladatele s externím iterátorem * Iterátor používá rekurzi k iteraci stromem prvků */ jmenný prostor compositeIterator { /** * Klient používá pro práci s objekty rozhraní AComponent. * Rozhraní AComponent definuje rozhraní pro všechny komponenty: jak kombinace, tak i koncové uzly. * AComponent může implementovat výchozí chování pro add() remove() getChild() a další operace */ abstract class AComponent { public $customPropertyName ; public $customPropertyDescription ; /** * @param AComponent $component */ public function add ( $component ) { throw new \Exception ( "Nepodporovaná operace" ); } /** * @param AComponent $component */ public function remove ( $component ) { throw new \Exception ( "Nepodporovaná operace" ); } /** * @param int $int */ public function getChild ( $int ) { throw new \Exception ( "Nepodporovaná operace" ); } /** * @return IPhpLikeIterator */ abstract function createIterator (); public function operation1 () { throw new \Exception ( "Nepodporovaná operace" ); } } /** * Leaf zdědí metody add() remove() getChild(, které nemusí dávat smysl pro listový uzel. * Ačkoli listový uzel lze považovat za uzel s nulovými potomky * * List definuje chování prvků kombinace. Za tímto účelem implementuje operace podporované složeným rozhraním */ class Leaf extends AComponent { public function __construct ( $name , $description = '' ) { $this -> customPropertyName = $name ; $this -> customPropertyDescription = $description ; } public function createIterator () { return new NullIterator (); } public function operation1 () { echo ( " \n Jsem list { $this -> customPropertyName } , nechci dělat operaci 1. { $this -> customPropertyDescription } " ); } } class NullIterator implementuje IPhpLikeIterator { public function valid () { return ( false ); } public function next () { return ( false ); } public function current () { return ( null ); } public function remove () { throw new \CException ( 'nepodporovaná operace' ); } } /** * Kompozitní rozhraní definuje chování komponent, které mají potomky, a poskytuje jim úložiště. * * Composite také implementuje operace související s listem. Některé z nich nemohou nedávat smysl pro kombinace; v takových případech je vyvolána výjimka. */ class Composite rozšiřuje AComponent { private $_iterator = null ; /** * @var \ArrayObject AComponent[] $components pro uložení potomků typu AComponent */ public $components = null ; public function __construct ( $name , $description = '' ) { $this -> customPropertyName = $name ; $this -> customPropertyDescription = $description ; } /** * @param AComponent $component */ public function add ( $component ) { if ( is_null ( $this -> komponenty )) { $this -> komponenty = new \ArrayObject ; } $this -> komponenty -> append ( $component ); } public function remove ( $component ) { foreach ( $this -> komponenty as $i => $c ) { if ( $c === $component ) { unset ( $this -> komponenty [ $i ]); } } } public function getChild ( $int ) { return ( $this -> komponenty [ $int ]); } public function operation1 () { echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; echo " \n --------------------------------" ; $iterator = $this -> komponenty -> getIterator (); while ( $iterátor -> platný ()) { $komponenta = $iterátor -> aktuální (); $komponenta -> operace1 (); $iterator -> dalsi (); } } /** * @return CompositeIterator */ public function createIterator () { if ( is_null ( $this -> _iterator )) { $this -> _iterator = new CompositeIterator ( $this -> komponenty -> getIterator ()); } return ( $this -> _iterator ); } } /** * Rekurzivní složený iterátor */ class CompositeIterator implementuje IPhpLikeIterator { public $stack = pole (); /** * @param \ArrayIterator $componentsIterator */ public function __construct ( $componentsIterator ) { //$this->stack= new \ArrayObject; $this -> stack [] = $componentsIterator ; } public function remove () { throw new \CException ( 'nepodporovaná operace' ); } public function valid () { if ( empty ( $this -> stack )) { return ( false ); } else { /** @var $componentsIterator \ArrayIterator */ // získá první prvek $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 = aktuální ( $this -> stack ); $component = $componentsIterator -> aktuální (); if ( $component instanceof Composite ) { array_push ( $this -> stack , $component -> createIterator ()); } $componentsIterator -> další (); //return($komponenta); } public function current () { if ( $this -> valid ()) { /** @var $componentsIterator \ArrayIterator */ // získání prvního prvku $componentsIterator = array_shift ( array_values ​​​​( $this -> stack )) ; return ( $componentsIterator -> aktuální ()); } else { return ( null ); } } } /** * Rozhraní iterátoru musí být implementováno všemi iterátory. * Toto rozhraní je součástí standardního rozhraní iterátoru php. * Konkrétní iterátor je zodpovědný za správu aktuální pozice iterace v konkrétní kolekci. */ interface IPhpLikeIterator { /** * @abstrakt * @return boolean je aktuální prvek */ public function valid (); /** * @abstrakt * @return smíšený přesun kurzoru dále */ public function next (); /** * @abstract * @return mixed získat aktuální prvek */ public function current (); /** * odstranění aktuálního prvku kolekce * @abstract * @return void */ public function remove (); } class Klient { /** * @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 ( $iterator -> valid ()) { /** @var $component AComponent */ $component = $iterator -> current (); if ( strstr ( $component -> customPropertyName , 'leaf1' )) { echo ( " \n Jsem klient, našel jsem list { $component -> customPropertyName } , nechám to zde (pro můj 'první- sbírka čajů z listů). { $component -> customPropertyDescription } " ); } $iterator -> dalsi (); } } } class Test { public static function go () { $a = new Composite ( "c1" ); $b = nový kompozit ( "c2" ); $c = nový kompozit ( "c3" ); $topItem = new Composite ( "top item" ); $topItem -> add ( $a ); $topItem -> add ( $b ); $topItem -> add ( $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" )); $klient = nový klient ( $topItem ); $klient -> tiskOperace1 (); $client -> printOperation2 (); } } test :: jít (); }

Python

Zdrojový kód v Pythonu z abc import ABCMeta , abstraktní metoda iterátor třídy ( metaclass = ABCMeta ): """ Abstraktní iterátor """ _error = Žádná # třída chyby, která je vyvolána, pokud je kolekce mimo rozsah def __init__ ( self , kolekce , kurzor ): """ Konstruktor. :param collection: kolekce, kterou má iterátor procházet :param kurzor: počáteční pozice kurzoru v kolekci (klíč) """ self ._collection = kolekce self ._cursor = kurzor @abstractmethod def current ( self ): """ Vrátí aktuální prvek, na který ukazuje průchod iterátoru """ @abstractmethod def next ( self ): """ Přesuňte kurzor na další prvek v kolekci a vraťte jej """ pass @abstractmethod def has_next ( self ): """ Zkontrolujte, zda existuje další prvek kolekce """ pass @abstractmethod def remove ( self ): """ Odebere aktuální prvek kolekce, na kterou ukazuje kurzor """ pass def _raise_key_exception ( self ): """ Zvýšit neplatný index obsažený v kurzoru """ zvýšit self . _error ( 'Kolekce třídy {} nemá klíč " {} "' . formát ( self . __class__ . __name__ , self . _cursor )) class ListIterator ( Iterator ): """ Iterátor, který iteruje přes normální seznam """ _error = IndexError def __init__ ( self , kolekce : seznam ): super () . __init__ ( kolekce , 0 ) def aktuální ( self ): jestliže self . _cursor < len ( self . _collection ): return self . _kolekce [ vlastní . _cursor ] self . _raise_key_exception () def next ( self ): if len ( self . _collection ) >= self . _kurzor + 1 : vlastní . _cursor += 1 návrat self . _kolekce [ vlastní . _cursor ] self . _raise_key_exception () def has_next ( self ): return len ( self . _collection ) >= self . _kurzor + 1 def remove ( self ): if 0 <= self . _cursor < len ( self . _collection ): self . _kolekce . odebrat ( self . _collection [ self . _cursor ]) else : self . _raise_key_exception () class DictIterator ( Iterator ): """ Iterátor slovníku - vzhledem k tomu, že slovníky v Pythonu jsou implementovány jako hashovací tabulky, může se pořadí procházení během různých běhů měnit """ _error = KeyError def __init__ ( self , kolekce : dict ): super () . __init__ ( kolekce , další ( iter ( kolekce ))) self . _keys = seznam ( self . _collection . keys ()) self . _klíče . pop ( 0 ) def aktuální ( self ): jestliže self . _kurzor v sobě . _kolekce : vrátit se . _kolekce [ vlastní . _cursor ] self . _raise_key_exception () def next ( self ): if len ( self . _keys ): self . _cursor = self . _klíče . pop ( 0 ) return self . _kolekce [ vlastní . _cursor ] else : self . _raise_key_exception () def has_next ( self ): return len ( self . _keys ) > 0 def remove ( self ): if self . _kurzor v sobě . _kolekce : del self . _kolekce [ vlastní . _cursor ] zkuste : sebe . další () kromě sebe . _error : raise KeyError ( 'Kolekce typu {} je prázdná' . format ( self . __class__ . __name__ )) else : self . _raise_key_exception () class Collection ( metaclass = ABCMeta ): """ Abstraktní kolekce """ @abstractmethod def iterator ( self ): pass class ListCollection ( Collection ): """ Kolekce obálky pro normální seznam """ def __init__ ( self , kolekce : seznam ): self . _kolekce = sběr def iterator ( self ): return ListIterator ( self . _collection ) class DictCollection ( Collection ): """ Kolekce Wrapper pro slovník """ def __init__ ( self , kolekce : dict ): self . _kolekce = sběr def iterator ( self ): return DictIterator ( self . _collection ) def test ( title = str , kolekce = Kolekce ): tisk ( " \n {} \n " . formát ( nadpis )) iterátor = kolekce . iterátor () tisk ( iterátor . aktuální ()) iterátor . další () tisk ( iterátor . další ()) iterátor . odebrat () tisknout ( iterátor . aktuální ()) tisknout ( iterátor . has_next ()) tisknout () if __name__ == '__main__' : print ( 'OUTPUT:' ) test ( 'Testování seznamu' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ])) test ( 'Testování slovníku' , DictCollection ({ 'a') : 1 , 'b' : 2 , 'c' : 3 , 'f' : 8 })) ''' VÝSTUP: Testování seznamu 1 3 4 Pravda Testování slovníku 1 3 2 Nepravda '''

Rez

Příklad rzi #[derive(Debug, Clone, Copy)] pub struct ExampleRange { začátek : i64 , aktuální : i64 , konec : i64 , } impl ExampleRange { pub fn new ( begin : i64 , end : i64 ) -> Self { PříkladRozsah { začít , aktuální : začít , konec , } } pub fn iter ( & self ) -> ExampleRange { * sebe } } použijte std :: fmt ; impl fmt :: Zobrazení pro ExampleRange { fn fmt ( & self , f : & mut fmt :: Formátovač <' _ > ) -> fmt :: Výsledek { napsat! ( f , " {} " , vlastní aktuální ) } } impl Iterator pro ExampleRange { typeItem = i64 ; _ fn next ( & mut self ) -> Option < Self :: Item > { pokud sám . aktuální < vlastní . konec { ( Některé ( vlastní . proud ), vlastní . proud += 1 ). 0 } jiný { Žádný } } fn last ( mut self ) -> Option < Self :: Item > { pokud sám . aktuální > vlastní . začít { ( vlastní . proud -= 1 , Některé ( vlastní . proud )). jeden } jiný { Žádný } } } fn main () { let it = ExampleRange :: new ( 0 , 6 ); pro položku v něm { println! ( "{}" , položka ); } } ''' VÝSTUP : 0 jeden 2 3 čtyři 5 '''