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 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:
- det er ikke klart, hvad værdien "end of aggregate" er, for en dobbelt linket liste er det &ListHead, for en matrix er det &array[størrelse], for en enkelt linket liste er det NULL
- Den næste operation er meget afhængig af typen af aggregat.
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
'''