Iterátor (tervezési minta)
Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2016. május 9-én felülvizsgált
verziótól ; az ellenőrzések 9 szerkesztést igényelnek .
Az Iterátor egy viselkedési tervezési minta . Olyan objektumot jelöl, amely szekvenciális hozzáférést tesz lehetővé egy összesített objektum elemeihez anélkül, hogy az egyes összesített objektumok leírását használná.
Például az olyan elemek, mint a fa , egy linkelt lista , egy hash tábla és egy tömb bejárhatók (és módosíthatók) egy Iterator objektum segítségével .
Az elemeken keresztüli iterációt az iterátor objektum végzi, nem maga a gyűjtemény. Ez leegyszerűsíti a gyűjtemény felületét és megvalósítását, és elősegíti a problémák logikusabb elkülönítését .
A teljesen megvalósított iterátor jellemzője, hogy az iterátort használó kód nem tudhat semmit az iterált aggregátum típusáról.
Természetesen (C++-ban) szinte minden aggregátum megismételhető void* mutatóval, de:
- nem világos, hogy mi az "összesített vége" érték, duplán linkelt listáknál &ListHead, tömbnél &array[size], egyszeri hivatkozású listáknál NULL
- A Next művelet nagymértékben függ az aggregátum típusától.
Az iterátorok lehetővé teszik egy aggregátum típusának és terminátorának absztrahálását a polimorf Next (C++-ban gyakran operátorként++) és a polimorf aggregate.end() segítségével, amely az "összesítés vége"-t adja vissza.
Így lehetővé válik az iterátorok tartományaival való munka, az iterált aggregátum típusának ismerete hiányában. Például:
Iterátor itBegin = aggregate . kezdődik ();
Iterátor itEnd = aggregátum . vége ();
func ( itBegin , itEnd );
És tovább:
void func ( Iterator itBegin , Iterator itEnd )
{
for ( Iterator it = itBegin , it != itEnd ; ++ it )
{
}
}
Példák
C#
Forrásszöveg
C# nyelven
/*
mintakód C#-ban
Ez a szerkezeti kód az Iterátor mintát mutatja be, amely lehetőséget biztosít a tételek gyűjteményének áthaladására (iterációra) anélkül, hogy részletezné a gyűjtemény mögöttes szerkezetét.
*/
kód elrejtése
// Iterátor minta -- Szerkezeti példa
a rendszer használatával ;
a System.Collections használatával ;
névtér DoFactory.GangOfFour.Iterator.Structural
{
/// <summary>
/// MainApp indítási osztály a Structural számára /// Iterátor
tervezési minta.
/// </summary>
class MainApp
{
/// <summary>
/// Belépési pont a konzolalkalmazásba.
/// </summary>
static void Main ()
{
ConcreteAggregate a = new ConcreteAggregate ();
a [ 0 ] = "A tétel" ;
a [ 1 ] = "B tétel" ;
a [ 2 ] = "C tétel" ;
a [ 3 ] = "D tétel" ;
// Iterátor létrehozása és összesített
ConcreteIterator megadása i = new ConcreteIterator ( a );
Konzol . WriteLine ( "Iteráció a gyűjtemény felett:" );
tárgyelem = i . _ első (); while (! i . IsDone ()) { Konzol . WriteLine ( elem ); item = i . következő (); }
// Várja meg a felhasználói
konzolt . ReadKey ();
}
}
/// <summary>
/// Az 'Aggregate' abstract class
/// </summary>
abstract class Aggregate
{
public abstract Iterator CreateIterator ();
public abstract int Szám { get ; védett készlet ; }
public absztrakt objektum this [ int index ] { get ; készlet ; }
}
/// <summary>
/// A 'ConcreteAggregate' osztály
/// </summary>
class ConcreteAggregate : Aggregate
{
private readonly ArrayList _items = new ArrayList ();
public override Iterator CreateIterator ()
{
return new ConcreteIterator ( this );
}
// Lekéri a cikkszámot
public override int Szám
{
get { return _items . gróf ; }
védett készlet { }
}
// Indexelő
nyilvános felülbíráló objektum this [ int index ]
{
get { return _items [ index ]; }
set { _items . beszúr ( index , érték ); }
}
}
/// <summary>
/// Az 'Iterátor' abstract class
/// </summary>
abstract class Iterátor
{
public abstract object Először ();
publikus absztrakt objektum Következő ();
public abstract bool IsDone ();
nyilvános absztrakt objektum CurrentItem ();
}
/// <summary>
/// A 'ConcreteIterator' osztály
/// </summary>
class ConcreteIterator : Iterator
{
private readonly Aggregate _aggregate ;
private int _current ;
// Constructor
public ConcreteIterator ( Aggregate aggregate )
{
this . _aggregate = összesítés ;
}
// Lekéri az első iterációs elemet
public override object First ()
{
return _aggregate [ 0 ];
}
// Lekéri a következő iterációs elemet
public override object Next ()
{
object ret = null ;
_current ++;
if ( _aktuális < _összesítő . Szám )
{
ret = _aggregate [ _current ];
}
return ret ;
}
// Lekéri az aktuális iterációs elemet
public override object CurrentItem ()
{
return _aggregate [ _current ];
}
// Lekérdezi, hogy az iterációk teljesek-e
nyilvános felülírás bool IsDone ()
{
return _current >= _aggregate . gróf ;
}
}
}
Kimenet
Iterálás a gyűjtemény felett : A tétel B tétel C tétel D
PHP5
PHP5 forráskód
/**
* Az iterátor minta mechanizmust biztosít a gyűjtemény elemei közötti iterációhoz anélkül, hogy felfedné a gyűjtemény megvalósítását.
*
* Az elemeken keresztüli iterációt az iterátor objektum végzi, nem maga a gyűjtemény.
* Ez leegyszerűsíti a gyűjtemény felületét és megvalósítását, valamint hozzájárul a felelősségek logikusabb elosztásához.
*/
namespace iterator1 {
/**
* A közös interfész kényelmes a kliens számára, mivel a kliens le van választva az objektumok gyűjteményének megvalósításáról.
*
* A ConcreteAggregate objektumok gyűjteményét tartalmazza, és olyan metódust valósít meg, amely egy iterátort ad vissza ehhez a gyűjteményhez.
*/
interface IAggregate
{
/**
* Minden ConcreteAggregate íz felelős egy Concrete Iterator példány létrehozásáért, amely
* használható az objektumok gyűjteményén keresztüli iterációra.
*/
nyilvános függvény createIterator ();
}
/**
* Az Iterátor felületet minden iterátornak implementálnia kell.
*
* A ConcreteIterator felelős az aktuális iterációs pozíció kezeléséért.
*/
interface IIterator
{
/**
* @abstract
* @return logikai érték van-e következő elem a gyűjteményben
*/
public function hasNext ();
/**
* @abstract
* @return kevert next tömbelem
*/
public function next ();
/**
* Eltávolítja a gyűjtemény aktuális elemét
* @abstract
* @return void
*/
public function remove ();
}
/**
* Az én példámban mindkét gyűjtemény ugyanazt az iterátort használja – egy tömb iterátort.
*/
class ConcreteAggregate1 megvalósítja az IAggregate-et
{
/**
* @var Item[] $items
*/
public $items = tömb ();
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 megvalósítja az IAggregate-et
{
/**
* @var Item[] $items
*/
public $items = tömb ();
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 implementálja az IIteratort
{
/**
* @var Item[] $elemek
*/
védett $elemek = tömb ();
/**
* @var int $pozíció tárolja az aktuális iterációs pozíciót a tömbben
*/
public $position = 0 ;
/**
* @param $items iterálandó objektumok tömbje
*/
public function __construct ( $items )
{
$this -> items = $items ;
}
public function hasNext ()
{
if ( $this -> position >= count ( $this -> items ) || count ( $this -> items ) == 0 ) {
return ( false );
} else {
return ( igaz );
}
}
public function next ()
{
$menuItem = $this -> items [ $this -> position ];
$this -> pozíció ++ ;
return ( $menuItem );
}
public function remove ()
{
if ( $this -> position <= 0 ) {
throw new \Exception ( 'Nem hívhatod meg az eltávolítást, mielőtt legalább egy next() meghívásra került' );
}
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
*/
public $aggregate1 ;
/**
* @var ConcreteAggregate2 $aggregate2
*/
public $aggregate2 ;
public function __construct ( $aggregate1 , $aggregate2 )
{
$this -> aggregate1 = $aggregate1 ;
$this -> aggregate2 = $aggregate2 ;
}
public function printAggregatesItems ()
{
$iterátor1 = $this -> aggregate1 -> createIterator ();
echo " \ nElőször" ;
$this -> printIteratorItems ( $iterator1 );
$iterátor2 = $this -> aggregate2 -> createIterator ();
echo " \n\ nSecond" ;
$this -> printIteratorItems ( $iterator2 );
}
/**
* @param $iterator IIterator
*/
private function printIteratorItems ( $iterator )
{
while ( $iterator -> hasNext ()) {
$item = $iterator -> next ();
echo " \n $cikk->név $cikk->ár $cikk->leírás " ; } } }
class Item
{
public $price ;
nyilvános $név ;
nyilvános $leírás ;
public function __construct ( $név , $ár , $leírás = '' )
{
$this -> name = $name ;
$ez -> ár = $ár ;
$this -> description = $leírás ;
}
}
$futó = új ügyfél ( new ConcreteAggregate1 (), new ConcreteAggregate2 ());
$futó -> printAggregatesItems ();
}
PHP5 builder iterator példa
PHP5 builder iterator forráskód
/**
* Composer minta külső iterátorral
* Az iterátor rekurziót használ az elemek fán való iterációhoz
*/
namespace compositeIterator {
/**
* A kliens az AComponent felületet használja az objektumokkal való munkavégzéshez.
* Az AComponent interfész az összes komponens interfészt határozza meg: mind a kombinációk, mind a levél csomópontok számára.
* Az AComponent alapértelmezett viselkedést valósíthat meg az add() remove() getChild() és egyéb műveleteknél
*/
abstract class AComponent
{
nyilvános $customPropertyName ;
nyilvános $customPropertyDescription ;
/**
* @param AComponent $komponens
*/
public function add ( $komponens )
{
throw new \Exception ( "Nem támogatott művelet" );
}
/**
* @param AComponent $komponens
*/
public function remove ( $komponens )
{
throw new \Exception ( "Nem támogatott művelet" );
}
/**
* @param int $int
*/
public function getChild ( $int )
{
throw new \Exception ( "Nem támogatott művelet" );
}
/**
* @return IPhpLikeIterator
*/
absztrakt függvény createIterator ();
public function operation1 ()
{
throw new \Exception ( "Nem támogatott művelet" );
}
}
/**
* A Leaf örökli az add() remove() getChild( metódusokat, aminek nem biztos, hogy értelme van egy levélcsomópont esetén.
* Bár a levélcsomópontot nulla gyermekes csomópontnak tekinthetjük
*
* A Leaf határozza meg a Ehhez a Composite interface által támogatott műveleteket valósítja meg
*/
class Leaf extends AComponent
{
public function __construct ( $name , $description = '' )
{
$this -> customPropertyName = $name ;
$this -> customPropertyDescription = $leírás ;
}
public function createIterator ()
{
return new NullIterator ();
}
public function operation1 ()
{
echo ( " \n Level vagyok { $this -> customPropertyName } , nem akarom elvégezni az 1. műveletet. { $this -> customPropertyDescription } " ); } }
class NullIterator implementálja az IPhpLikeIterator
{
public function valid ()
{
return ( false );
}
public function next ()
{
return ( false );
}
public function current ()
{
return ( null );
}
public function remove ()
{
throw new \CEexception ( 'nem támogatott művelet' );
}
}
/**
* A Composite felület meghatározza azon összetevők viselkedését, amelyeknek gyermekei vannak, és tárhelyet biztosít számukra.
*
* A Composite Leaf-specifikus műveleteket is megvalósít. Némelyikük nem ismeri a kombinációk értelmét; ilyen esetekben kivételt dobnak.
*/
class Composite kiterjeszti AComponent
{
private $_iterator = null ;
/**
* @var \ArrayObject AComponent[] $összetevők az AComponent típusú gyermek tárolására
*/
public $components = null ;
public function __construct ( $name , $description = '' )
{
$this -> customPropertyName = $name ;
$this -> customPropertyDescription = $leírás ;
}
/**
* @param AComponent $komponens
*/
public function add ( $komponens )
{
if ( is_null ( $this -> komponensek )) {
$this -> komponensek = new \ArrayObject ;
}
$this -> összetevők -> hozzáfűzés ( $komponens );
}
public function remove ( $komponens )
{
foreach ( $this -> összetevők as $i => $c ) {
if ( $c === $komponens ) {
unset ( $this -> összetevők [ $i ]);
}
}
}
public function getChild ( $int )
{
return ( $this -> komponensek [ $int ]);
}
public function operation1 ()
{
echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; echo " \n --------------------------------" ;
$iterátor = $this -> összetevők -> getIterator ();
while ( $iterátor -> érvényes ()) {
$komponens = $iterátor -> aktuális ();
$komponens -> művelet1 ();
$iterátor -> következő ();
}
}
/**
* @return CompositeIterator
*/
public function createIterator ()
{
if ( is_null ( $this -> _iterator )) {
$this -> _iterator = new CompositeIterator ( $this -> összetevők -> getIterator ());
}
return ( $this -> _iterator );
}
}
/**
* Rekurzív kompozit iterátor
*/
class CompositeIterator implementálja az IPhpLikeIterator
{
public $verem = tömb ();
/**
* @param \ArrayIterator $componentsIterator
*/
public function __construct ( $componentsIterator )
{
//$this->stack= new \ArrayObject;
$this -> verem [] = $componentsIterator ;
}
public function remove ()
{
throw new \CEexception ( 'nem támogatott művelet' );
}
public function valid ()
{
if ( üres ( $this -> verem )) {
return ( false );
} else {
/** @var $componentsIterator \ArrayIterator */
// az első elem lekérése
$componentsIterator = array_shift ( array_values ( $this -> verem ));
if ( $componentsIterator -> érvényes ()) {
return ( igaz );
} else {
array_shift ( $this -> verem );
return ( $this -> valid ());
}
}
}
public function next ()
{
/** @var $componentsIterator \ArrayIterator */
$componentsIterator = aktuális ( $this -> verem );
$komponens = $komponensekIterátor -> áram ();
if ( $component instanceof Composite ) {
array_push ( $this -> verem , $component -> createIterator ());
}
$componentsIterator -> next ();
//return($komponens);
}
public function current ()
{
if ( $this -> valid ()) {
/** @var $componentsIterator \ArrayIterator */
// az első elem lekérése
$componentsIterator = array_shift ( array_values ( $this -> verem )) ;
return ( $componentsIterator -> current ());
} else {
return ( null );
}
}
}
/**
* Az Iterátor felületet minden iterátornak implementálnia kell.
* Ez az interfész a szabványos php iterator interfész része.
* Egy adott iterátor felelős egy adott gyűjtemény aktuális iterációs pozíciójának kezeléséért.
*/
interfész IPhpLikeIterator
{
/**
* @abstract
* @return logikai érték az aktuális elem
*/
érvényes nyilvános függvény ();
/**
* @abstract
* @return vegyes kurzor mozgatása tovább
*/
public function next ();
/**
* @abstract
* @return mix az aktuális elem lekérése
*/
public function current ();
/**
* a gyűjtemény aktuális elemének eltávolítása
* @abstract
* @return void
*/
public function remove ();
}
class Kliens
{
/**
* @varAComponent
*/
public $topItem ;
public function __construct ( $topItem )
{
$this -> topItem = $topItem ;
}
public function printOperation1 ()
{
$this -> topItem -> operation1 ();
}
public function printOperation2 ()
{
echo " \n\n\n " ;
$iterátor = $this -> topItem -> createIterator ();
while ( $iterátor -> érvényes ()) {
/** @var $komponens AComponent */
$komponens = $iterátor -> aktuális ();
if ( strstr ( $component -> customPropertyName , 'leaf1' )) {
echo ( " \n Ügyfél vagyok, megtaláltam a következőt: leaf { $component -> customPropertyName } , csak itt hagyom (az első- leafs' tea collection). { $component -> customPropertyDescription } " );
}
$iterátor -> következő ();
}
}
}
class Teszt
{
public static function go ()
{
$a = new Összetett ( "c1" );
$b = új kompozit ( "c2" );
$c = új kompozit ( "c3" );
$topItem = new Összetett ( "legfelső elem" );
$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" ));
$kliens = új kliens ( $topItem );
$kliens -> printOperation1 ();
$kliens -> printOperation2 ();
}
}
teszt :: megy ();
}
Python
Forráskód
Pythonban
abc importból ABCMeta , abstractmethod _
osztály iterátor ( metaclass = ABCMeta ):
"""
Absztrakt iterátor
"""
_error = Nincs # a hiba osztálya, amely akkor jelenik meg, ha a gyűjtemény határon kívül esik
def __init__ ( self , collection , cursor ):
"""
Konstruktor.
:param gyűjtemény: az iterátor által bejárandó gyűjtemény :param cursor: a kurzor kezdeti pozíciója a gyűjteményben (kulcs)
"""
self ._collection = collection self ._cursor = kurzor
@abstractmethod
def current ( self ):
""" Visszaadja az aktuális elemet, amelyre az iterátor
""" lépése mutatott
@abstractmethod
def next ( self ):
"""
Mozgassa a kurzort a gyűjtemény következő elemére, és adja vissza
"""
lépést
@abstractmethod
def has_next ( self ):
"""
Ellenőrizze, hogy létezik-e a gyűjtemény következő eleme
"""
pass
@abstractmethod
def remove ( self ):
"""
Távolítsa el a gyűjtemény aktuális elemét, amelyre a kurzor
"""
lépése mutat
def _raise_key_exception ( self ):
""" A kurzorban
található érvénytelen index
emelése """
self self . _error ( 'A(z) {} osztály gyűjteményének nincs kulcsa " {} "' . formátum ( self . __class__ . __name__ , self . _cursor ))
osztály ListIterator ( Iterátor ):
"""
Egy iterátor, amely egy normál listán
"""
_error = IndexError
def __init__ ( self , collection : list ):
szuper () . __init__ ( gyűjtemény , 0 )
def current ( self ):
ha önmaga . _cursor < len ( self . _collection ):
önmagát adja vissza . _gyűjtemény [ én . _cursor ] self . _raise_key_exception ()
def next ( self ):
if len ( self . _collection ) >= self . _kurzor + 1 :
saját . _cursor += 1
önmagát adja vissza . _gyűjtemény [ én . _cursor ] self . _raise_key_exception ()
def has_next ( self ):
return len ( self . _collection ) >= self . _kurzor + 1
def remove ( self ):
if 0 <= self . _kurzor < len ( self . _collection ):
én . _gyűjtemény . eltávolítás ( self . _collection [ self . _cursor ])
else :
self . _raise_key_exception ()
osztály DictIterator ( Iterator ):
""" Szótáriterátor
- mivel a Python szótárai
hash-táblázatként vannak implementálva, a bejárási sorrend a különböző futtatások során változhat
"""
_error = Kulcshiba
def __init__ ( self , collection : dict ):
szuper () . __init__ ( gyűjtemény , next ( iter ( gyűjtemény )))
self . _keys = lista ( self . _collection . keys ())
self . _keys . pop ( 0 )
def current ( self ):
ha önmaga . _kurzor önmagában . _ _collection : önmagát adja vissza . _gyűjtemény [ én . _cursor ] self . _raise_key_exception ()
def next ( self ):
if len ( self . _keys ):
self . _cursor = self . _keys . pop ( 0 )
return self . _gyűjtemény [ én . _cursor ]
else :
self . _raise_key_exception ()
def has_next ( self ):
return len ( self . _keys ) > 0
def remove ( self ):
if self . _kurzor önmagában . _ _gyűjtemény : del self . _gyűjtemény [ én . _cursor ] try : self . következő () kivéve én . _error : raise KeyError ( 'A {} típusú gyűjtemény üres' . formátum ( self . __class__ . __name__ )) else : self . _raise_key_exception ()
osztály Gyűjtemény ( metaclass = ABCMeta ):
"""
Absztrakt gyűjtemény
"""
@abstractmethod
def iterator ( self ):
át
osztály ListCollection ( Gyűjtemény ):
""" Burkológyűjtemény
egy normál listához
"""
def __init__ ( self , collection : list ):
self . _collection = gyűjtemény
def iterator ( self ):
return ListIterator ( self . _collection )
osztály DictCollection ( gyűjtemény ):
""" Burkológyűjtemény a "
" szótárhoz
def __init__ ( self , collection : dict ):
én . _collection = gyűjtemény
def iterator ( self ):
return DictIterator ( self . _collection )
def teszt ( cím = str , gyűjtemény = Gyűjtemény ):
print ( " \n {} \n " . formátum ( cím ))
iterator = gyűjtemény . iterator ()
print ( iterator . current ())
iterator . next ()
print ( iterator . next ())
iterator . eltávolítás ()
print ( iterátor . jelenlegi ())
print ( iterator . has_next ())
print ()
if __name__ == '__main__' :
print ( 'OUTPUT:' )
teszt ( 'Lista tesztelése' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ]))
teszt ( 'Szótár tesztelése' , DictCollection ({ 'a') : 1 , 'b' : 2 , 'c' : 3 , 'f' : 8 }))
''
KIMENET:
Lista tesztelés
1
3
4
Igaz
Szótári tesztelés
1
3
2
hamis
''''
Rozsda
Rozsda példa
#[származtatás (hibakeresés, klónozás, másolás)]
pub struct ExampleRange
{
kezdés :
i64 ,
áram :
i64 ,
vége :
i64 ,
}
impl ExampleRange
{
pub fn new ( eleje :
i64 , vége :
i64 ) ->
Self
{
Példatartomány
{
kezdeni ,
jelenlegi :
kezdődik ,
vége ,
}
}
pub fn iter ( & self ) ->
ExampleRange
{
* önmaga
}
}
használd std ::
fmt ;
impl fmt ::
Az ExampleRange megjelenítése
{
fn fmt ( & self , f :
& mut fmt ::
Formátum <' _ > ) ->
fmt ::
Eredmény
{
ír! ( f , "{}" , saját . aktuális )
}
}
impl Iterátor az ExampleRange számára
{
typeItem = i64 ; _
fn next ( & mut self ) ->
Option < Self ::
Item >
{
ha önmaga . jelenlegi < én . vége
{
( Egyes ( saját . áram ), saját . áram += 1 ). 0
}
más
{
Egyik sem
}
}
fn last ( mut self ) ->
Option < Self ::
Item >
{
ha önmaga . jelenlegi > én . kezdődik
{
( self . current -= 1 , Some ( self . current )). egy
}
más
{
Egyik sem
}
}
}
fn fő ()
{
let it = PéldaTartomány ::
new ( 0 , 6 );
a benne lévő tételhez
{
println! ( "{}" , elem );
}
}
''''
KIMENET :
0
egy
2
3
négy
5
''''