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 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:
- není jasné, jaká je hodnota "end of agregace", pro dvojitě propojený seznam je to &ListHead, pro pole je to &array[velikost], pro jednoduše propojený seznam je to NULL
- Další operace je velmi závislá na typu agregátu.
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
'''