Iterator (model de proiectare)
Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de
versiunea revizuită pe 9 mai 2016; verificările necesită
9 modificări .
Iteratorul este un model de design comportamental . Reprezintă un obiect care permite accesul secvenţial la elementele unui obiect agregat fără a utiliza descrieri ale fiecăruia dintre obiectele agregate.
De exemplu, elemente precum un arbore , o listă legată , un tabel hash și o matrice pot fi parcurse (și modificate) folosind un obiect Iterator .
Iterarea prin elemente este făcută de obiectul iterator, nu de colecția în sine. Acest lucru simplifică interfața și implementarea colecției și promovează o separare mai logică a preocupărilor .
O caracteristică a unui iterator complet implementat este că codul care utilizează iteratorul poate să nu știe nimic despre tipul agregatului iterat.
Desigur, (în C++) aproape orice agregat poate fi repetat cu un pointer void*, dar:
- nu este clar care este valoarea „sfârșitul agregatului”, pentru o listă dublu legată este &ListHead, pentru o matrice este &array[size], pentru o listă legată individual este NULL
- Operația următoare depinde foarte mult de tipul de agregat.
Iteratoarele vă permit să abstrageți tipul și terminatorul unui agregat folosind Next polimorful (adesea implementat ca operator++ în C++) și agregatul polimorf.end() care returnează „sfârșitul agregatului”.
Astfel, devine posibil să se lucreze cu game de iteratoare, în absența cunoștințelor despre tipul de agregat iterat. De exemplu:
Iterator itBegin = agregat . începe ();
Iterator itEnd = agregat . sfârşitul ();
func ( itBegin , itEnd );
Și mai departe:
void func ( Iterator itBegin , Iterator itEnd )
{
pentru ( Iterator it = itBegin , it != itEnd ; ++ it )
{
}
}
Exemple
C#
Text sursă în
C#
/*
exemplu de cod în C#
Acest cod structural demonstrează modelul Iterator care oferă o modalitate de a parcurge (itera) o colecție de articole fără a detalia structura de bază a colecției.
*/
ascunde codul
// Model iterator -- Exemplu structural
folosind System ;
folosind System.Collections ;
namespace DoFactory.GangOfFour.Iterator.Structural
{
/// <summary>
/// Clasa de pornire MainApp pentru Structural
/// Iterator Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Punct de intrare în aplicația consolă.
/// </summary>
static void Main ()
{
ConcreteAggregate a = new ConcreteAggregate ();
a [ 0 ] = „Articol A” ;
a [ 1 ] = „Articol B” ;
a [ 2 ] = „Articol C” ;
a [ 3 ] = „Articol D” ;
// Creați Iterator și furnizați ConcreteIterator agregat i = new ConcreteIterator ( a );
Consola . WriteLine ( "Iterarea peste colecție:" );
obiect obiect = i . primul ();
în timp ce (! i . IsDone ())
{
Consolă . WriteLine ( element );
item = i . următorul ();
}
// Așteptați
Consola utilizatorului . ReadKey ();
}
}
/// <summary>
/// Clasa abstractă „Aggregate”
/// </summary>
abstract class Aggregate
{
public abstract Iterator CreateIterator ();
public abstract int Număr { get ; set protejat ; } obiect abstract public this [ int index ] { get ; set ; } }
/// <summary>
/// Clasa 'ConcreteAggregate'
/// </summary>
clasa ConcreteAggregate : Aggregate
{
private readonly ArrayList _items = new ArrayList ();
public override Iterator CreateIterator ()
{
return new ConcreteIterator ( this );
}
// Obține numărul de articole
public override int Count
{
get { return _items . numără ; }
set protejat { } }
// Indexator
public override obiect this [ int index ]
{
get { return _items [ index ]; }
set { _items . inserare ( index , valoare ); }
}
}
/// <summary>
/// Clasa abstractă 'Iterator'
/// </summary>
abstract class Iterator
{
obiect abstract public First (); obiect abstract public Next (); public abstract bool IsDone (); obiect abstract public CurrentItem (); }
/// <summary>
/// Clasa 'ConcreteIterator'
/// </summary>
class ConcreteIterator : Iterator
{
private readonly Aggregate _aggregate ;
private int _current ;
// Constructor
public ConcreteIterator ( Agregat agregat )
{
this . _agregat = agregat ;
}
// Obține primul element de iterație
public override object First ()
{
return _aggregate [ 0 ];
}
// Obține următoarea iterație element
public override object Next ()
{
object ret = null ;
_actual ++;
if ( _current < _aggregate . Count )
{
ret = _aggregate [ _current ];
}
return ret ;
}
// Obține elementul de iterație curent
public override object CurrentItem ()
{
return _aggregate [ _current ];
}
// Obține dacă iterațiile sunt complete
public override bool IsDone ()
{
return _current >= _aggregate . numără ;
}
}
}
Ieșire
Repetare peste colecție :
Element A
Element B
Element C
Element D
PHP5
Cod sursă
PHP5
/**
* Modelul iterator oferă un mecanism de iterare prin elementele unei colecții fără a expune implementarea colecției.
*
* Iterarea prin elemente este făcută de obiectul iterator, nu de colecția în sine.
* Acest lucru simplifică interfața și implementarea colecției și, de asemenea, contribuie la o distribuție mai logică a responsabilităților.
*/
namespace iterator1 {
/**
* A avea o interfață comună este convenabilă pentru client deoarece clientul este decuplat de implementarea colecției de obiecte.
*
* ConcreteAggregate conține o colecție de obiecte și implementează o metodă care returnează un iterator pentru această colecție.
*/
interface IAggregate
{
/**
* Fiecare aromă ConcreteAggregate este responsabilă pentru crearea unei instanțe Concrete Iterator care
* poate fi folosită pentru a itera colecțiile sale de obiecte.
*/
funcția publică createIterator (); }
/**
* Interfața Iterator trebuie implementată de toți iteratorii.
*
* ConcreteIterator este responsabil pentru gestionarea poziției curente de iterație.
*/
interface IIterator
{
/**
* @abstract
* @return boolean există un element următor în colecție
*/
public function hasNext ();
/**
* @abstract
* @return mixed next array element
*/
public function next ();
/**
* Îndepărtează elementul curent al colecției
* @abstract
* @return void
*/
public function remove ();
}
/**
* În exemplul meu, ambele colecții folosesc același iterator - un iterator de matrice.
*/
clasa ConcreteAggregate1 implementează IAggregate
{
/**
* @var Item[] $items
*/
public $items = array ();
public function __construct ()
{
$this -> items = array (
nou Item ( 1 , 2 ),
nou Item ( 1 , 2 ),
nou Item ( 1 , 2 ),
);
}
public function createIterator ()
{
return new ConcreteIterator1 ( $this -> items );
}
}
clasa ConcreteAggregate2 implementează IAggregate
{
/**
* @var Item[] $items
*/
public $items = array ();
public function __construct ()
{
$this -> items = array (
nou Item ( 2 , 3 ),
nou Item ( 2 , 3 ),
nou Item ( 2 , 3 ),
);
}
public function createIterator ()
{
return new ConcreteIterator1 ( $this -> items );
}
}
clasa ConcreteIterator1 implementează IIterator
{
/**
* @var Item[] $items
*/
protected $items = array ();
/**
* @var int $position stochează poziția curentă de iterație în matrice
*/
public $position = 0 ;
/**
* @param $items matrice de obiecte pe care să le iterați peste
*/
public function __construct ( $items )
{
$this -> items = $items ;
}
funcția publică areNext ()
{
dacă ( $acest -> poziție >= număr ( $acest -> articole ) || număr ( $acest -> articole ) == 0 ) {
return ( fals );
} else {
return ( adevărat );
}
}
public function next ()
{
$menuItem = $this -> items [ $this -> position ];
$acest -> poziție ++ ;
return ( $menuItem );
}
public function remove ()
{
if ( $this -> position <= 0 ) {
throw new \Exception ( 'Nu poți apela remove înainte ca cel puțin un next() să fi fost apelat' );
}
if ( $acest -> elemente [ $acest -> poziție - 1 ] != nul ) {
pentru ( $i = $acest -> poziție - 1 ; $i < număr ( $acest -> articole ); $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 ;
function public __construct ( $ agregat1 , $agregat2 )
{
$acest -> agregat1 = $agregat1 ;
$acest -> agregat2 = $agregat2 ;
}
public function printAggregatesItems ()
{
$iterator1 = $this -> aggregate1 -> createIterator ();
echo " \ nPrimul" ;
$this -> printIteratorItems ( $iterator1 );
$iterator2 = $this -> aggregate2 -> createIterator ();
echo " \n\ nAl doilea" ;
$this -> printIteratorItems ( $iterator2 );
}
/**
* @param $iterator IIterator
*/
private function printIteratorItems ( $iterator )
{
while ( $iterator -> hasNext ()) {
$item = $iterator -> urmatorul ();
echo " \n $articol->nume $articol->preț $articol->descriere " ; } } }
class Item
{
public $price ;
public $nume ;
public $descriere ;
function public __construct ( $nume , $pret , $descriere = '' )
{
$acest -> nume = $nume ;
$acest -> preț = $preț ;
$this -> description = $descriere ;
}
}
$runner = client nou ( nou ConcreteAggregate1 (), nou ConcreteAggregate2 ()); $runner -> printAggregatesItems (); }
Exemplu de iterator PHP5 builder
Cod sursă iterator PHP5 builder
/**
* Model de compozitor cu iterator extern
* Iteratorul folosește recursiunea pentru a itera prin arborele de elemente
*/
namespace compositeIterator {
/**
* Clientul folosește interfața AComponent pentru a lucra cu obiecte.
* Interfața AComponent definește interfața pentru toate componentele: atât combinații, cât și nodurile frunză.
* AComponent poate implementa comportamentul implicit pentru add() remove() getChild() și alte operațiuni
*/
abstract class AComponent
{
public $customPropertyName ;
public $customPropertyDescription ;
/**
* @param AComponent $component
*/
public function add ( $component )
{
throw new \Exception ( "Operatie nesuportata" );
}
/**
* @param AComponent $component
*/
public function remove ( $component )
{
throw new \Exception ( "Operatie nesuportata" );
}
/**
* @param int $int
*/
public function getChild ( $int )
{
throw new \Exception ( "Operatie nesuportata" );
}
/**
* @return IPhpLikeIterator
*/
funcția abstractă createIterator ();
public function operation1 ()
{
throw new \Exception ( "Operatiune nesuportata" );
}
}
/**
* Leaf moștenește metodele add() remove() getChild(, care ar putea să nu aibă sens pentru un nod frunză.
* Deși un nod frunză poate fi considerat un nod cu zero copii
*
* Frunza definește comportamentul elementelor din o combinație. Pentru a face acest lucru, implementează operațiunile suportate de interfața Composite
*/
class Leaf extends AComponent
{
public function __construct ( $nume , $descriere = '' )
{
$this -> customPropertyName = $name ;
$this -> customPropertyDescription = $descriere ;
}
public function createIterator ()
{
return new NullIterator ();
}
public function operation1 ()
{
echo ( " \n Sunt frunza { $this -> customPropertyName } , nu vreau sa fac operatia 1. { $this -> customPropertyDescription } " );
}
}
clasa NullIterator implementează IPhpLikeIterator
{
public function valid ()
{
return ( false );
}
public function next ()
{
return ( false );
}
public function current ()
{
return ( null );
}
public function remove ()
{
throw new \CException ( 'operațiune nesuportată' );
}
}
/**
* Interfața Composite definește comportamentul componentelor care au copii și asigură stocarea acestora.
*
* Compozitul implementează și operațiuni legate de frunze. Unele dintre ele nu pot să nu aibă sens pentru combinații; în astfel de cazuri se aruncă o excepție.
*/
class Composite extinde AComponent
{
privat $_iterator = null ;
/**
* @var \ArrayObject AComponent[] $componente pentru a stoca copii de tip AComponent
*/
public $components = null ;
function public __construct ( $nume , $descriere = '' )
{
$this -> customPropertyName = $nume ;
$this -> customPropertyDescription = $descriere ;
}
/**
* @param AComponent $component
*/
public function add ( $component )
{
if ( is_null ( $this -> components )) {
$this -> components = new \ArrayObject ;
}
$this -> components -> append ( $component );
}
public function remove ( $component )
{
foreach ( $this -> componente ca $i => $c ) {
if ( $c === $component ) {
unset ( $this -> componente [ $i ]);
}
}
}
function public getChild ( $int )
{
return ( $this -> componente [ $int ]);
}
public function operation1 ()
{
echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; ecou " \n --------------------------------" ;
$iterator = $this -> componente -> getIterator ();
while ( $iterator -> valid ()) {
$component = $iterator -> curent ();
$componenta -> operatiune1 ();
$iterator -> următorul ();
}
}
/**
* @return CompositeIterator
*/
public function createIterator ()
{
if ( is_null ( $this -> _iterator )) {
$this -> _iterator = new CompositeIterator ( $this -> componente -> getIterator ());
}
return ( $this -> _iterator );
}
}
/**
* Iterator recursiv compus
*/
clasa CompositeIterator implementează IPhpLikeIterator
{
public $stiva = matrice ();
/**
* @param \ArrayIterator $componentsIterator
*/
public function __construct ( $componentsIterator )
{
//$this->stack= new \ArrayObject;
$this -> stack [] = $componentsIterator ;
}
public function remove ()
{
throw new \CException ( 'operațiune nesuportată' );
}
function public valid ()
{
if ( empty ( $this -> stack )) {
return ( false );
} else {
/** @var $componentsIterator \ArrayIterator */
// obține primul element
$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 = curent ( $this -> stack );
$component = $componentsIterator -> curent ();
if ( $component instanceof Composite ) {
array_push ( $this -> stack , $component -> createIterator ());
}
$componentsIterator -> next ();
//return($component);
}
funcția publică curent ()
{
dacă ( $this -> valid ()) {
/** @var $componentsIterator \ArrayIterator */
// obține primul element
$componentsIterator = array_shift ( array_values ( $this -> stack )) ;
return ( $componentsIterator -> curent ());
} else {
return ( null );
}
}
}
/**
* Interfața Iterator trebuie implementată de toți iteratorii.
* Această interfață face parte din interfața standard php iterator.
* Un anumit Iterator este responsabil pentru gestionarea poziției curente de iterație într-o anumită colecție.
*/
interface IPhpLikeIterator
{
/**
* @abstract
* @return boolean este elementul curent
*/
public function valid ();
/**
* @abstract
* @return mixt muta cursorul mai departe
*/
public function next ();
/**
* @abstract
* @return mixed obține elementul curent
*/
public function current ();
/**
* elimina elementul curent al colecției
* @abstract
* @return void
*/
public function remove ();
}
clasă Client
{
/**
* @varAComponent
*/
public $topItem ;
function public __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 -> curent ();
if ( strstr ( $component -> customPropertyName , 'leaf1' )) {
echo ( " \n Sunt Client, am găsit frunza { $component -> customPropertyName } , o voi lăsa aici (pentru "primul meu- colecția de ceai a frunzelor). { $component -> customPropertyDescription } " );
}
$iterator -> următorul ();
}
}
}
class Test
{
public static function go ()
{
$a = new Composite ( "c1" );
$b = nou Compozit ( "c2" );
$c = nou Compozit ( "c3" );
$topItem = nou Compozit ( "articol de sus" );
$topItem -> adaugă ( $a );
$topItem -> adaugă ( $b );
$topItem -> adaugă ( $c );
$a -> adaugă ( frunză nouă ( "c1-leaf1" )); $a -> adaugă ( frunză nouă ( "c1-leaf2" ));
$b -> adaugă ( frunză nouă ( "c2-leaf1" )); $b -> adaugă ( frunză nouă ( "c2-leaf2" )); $b -> adaugă ( frunză nouă ( "c2-leaf3" ));
$c -> adaugă ( frunză nouă ( "c3-leaf1" )); $c -> adaugă ( frunză nouă ( "c3-leaf2" ));
$client = client nou ( $topItem ); $client -> printOperation1 (); $client -> printOperation2 (); } }
test :: du-te ();
}
Python
Cod sursă în
Python
din abc import ABCMeta , abstractmethod
Iterator de clasă ( metaclasă = ABCMeta ):
"""
Iterator abstract
"""
_error = None # clasa erorii care este aruncată dacă colecția este în afara limitelor
def __init__ ( self , collection , cursor ):
"""
Constructor.
:param collection: colecția care trebuie străbătută de iterator :param cursor: poziția inițială a cursorului în colecția (cheie)
"""
self ._collection = colecție self ._cursor = cursor
@abstractmethod
def current ( self ):
"""
Returnează elementul curent indicat de trecerea iteratorului
" ""
@abstractmethod
def next ( self ):
"""
Mutați cursorul la următorul element din colecție și returnați-l
"""
pass
@abstractmethod
def has_next ( self ):
"""
Verificați dacă următorul element al colecției există
"""
trece
@abstractmethod
def remove ( self ):
"""
Eliminați elementul curent al colecției indicat de cursorul
"""
trece
def _raise_key_exception ( self ):
"""
Ridicați un index nevalid conținut în cursorul
"""
raise self . _error ( „Colecția clasei {} nu are cheia „ {} ”’ . format (
self . __class__ . __name__ , self . _cursor ))
class ListIterator ( Iterator ):
"""
Un iterator care iterează peste o listă normală
"""
_error = IndexError
def __init__ ( self , collection : list ):
super () . __init__ ( colecție , 0 )
def curent ( self ):
if self . _cursor < len ( self . _collection ):
return self . _colecție [ self . _cursor ]
self . _raise_key_exception ()
def next ( self ):
if len ( self . _collection ) >= self . _cursor + 1 :
sine . _cursor += 1
returnează sine . _colecție [ self . _cursor ]
self . _raise_key_exception ()
def are_next ( self ):
return len ( self . _collection ) >= self . _cursor + 1
def remove ( self ):
if 0 <= self . _cursor < len ( self . _collection ):
self . _colecție . elimina ( self . _colecție [ self . _cursor ])
else :
self . _raise_key_exception ()
clasa DictIterator ( Iterator ):
"""
Iterator de dicționar - datorită faptului că dicționarele în Python sunt implementate
ca tabele hash, ordinea de traversare se poate schimba în timpul diferitelor rulări
"""
_error = KeyError
def __init__ ( self , collection : dict ):
super () . __init__ ( colecție , următor ( iter ( colecție )))
sine . _keys = listă ( self . _colecție . chei ())
self . _chei . pop ( 0 )
def curent ( self ):
if self . _cursor în sine . _colecție :
return self . _colecție [ self . _cursor ]
self . _raise_key_exception ()
def next ( self ):
if len ( self . _keys ):
self . _cursor = self . _chei . pop ( 0 )
return self . _colecție [ self . _cursor ]
else :
sine . _raise_key_exception ()
def are_next ( self ):
return len ( self . _keys ) > 0
def remove ( self ):
dacă self . _cursor în sine . _colecție :
del self . _colecție [ self . _cursor ]
try :
self . următorul ()
cu excepția sinelui . _error :
ridicați KeyError ( 'Colecția de tip {} este goală' . format ( self . __class__ . __name__ ))
else :
self . _raise_key_exception ()
Class Collection ( metaclass = ABCMeta ):
"""
Colecție abstractă
"""
@abstractmethod
def iterator ( self ):
trece
class ListCollection ( Collection ):
"""
O colecție wrapper pentru o listă normală
"""
def __init__ ( self , collection : list ):
self . _colecție = colecție
def iterator ( self ):
returnează ListIterator ( self . _collection )
clasa DictCollection ( Colecție ):
"""
Colecție Wrapper pentru dicționar
"""
def __init__ ( self , collection : dict ):
self . _colecție = colecție
def iterator ( self ):
return DictIterator ( self . _collection )
def test ( title = str , collection = Collection ):
print ( " \n {} \n " . format ( title ))
iterator = collection . iterator ()
print ( iterator . curent ())
iterator . următorul ()
print ( iterator . următorul ())
iterator . elimina ()
print ( iterator . curent ())
print ( iterator . are_next ())
imprimare ()
if __name__ == '__main__' :
print ( 'OUTPUT:' )
test ( 'Testarea listei' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ]))
test ( 'Testarea dictionarului' , DictCollection ({ 'a' : 1 , „b” : 2 , „c” : 3 , „f” : 8 }))
'''
IEȘIRE:
Lista de testare
1
3
4
Adevărat
Dicţionar testing
1
3
2
Fals
'''
Rugina
Exemplu
de rugina
#[deriva (Depanare, Clonare, Copiere)]
pub struct ExampleRange
{
începe :
i64 ,
curent :
i64 ,
sfârşit :
i64 ,
}
impl ExampleRange
{
pub fn new ( început :
i64 , sfârșit :
i64 ) ->
Self
{
ExampleRange
{
incepe ,
curent :
începe ,
sfarsit ,
}
}
pub fn iter ( & self ) ->
ExampleRange
{
* sine
}
}
utilizați std ::
fmt ;
impl fmt ::
Afișează pentru ExampleRange
{
fn fmt ( & self , f :
& mut fmt ::
Formatter <' _ > ) ->
fmt ::
Rezultat
{
scrie! ( f , " {} " , sine . curent )
}
}
impl Iterator pentru ExampleRange
{
typeItem = i64 ; _
fn next ( & mut self ) ->
Opțiune < Self ::
Item >
{
dacă sine . curent < sine . Sfârşit
{
( Unii ( self . current ), self . current += 1 ). 0
}
altfel
{
Nici unul
}
}
fn last ( mut self ) ->
Opțiune < Self ::
Item >
{
dacă sine . curent > sine . ÎNCEPE
{
( self . current -= 1 , Unii ( self . current )). unu
}
altfel
{
Nici unul
}
}
}
fn principal ()
{
let it = ExampleRange ::
new ( 0 , 6 );
pentru elementul din el
{
println! ( "{}" , element );
}
}
'''
IEȘIRE :
0
unu
2
3
patru
5
'''