Iterador (patrón de diseño)
La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la
versión revisada el 9 de mayo de 2016; las comprobaciones requieren
9 ediciones .
Iterator es un patrón de diseño de comportamiento . Representa un objeto que permite el acceso secuencial a los elementos de un objeto agregado sin usar descripciones de cada uno de los objetos agregados.
Por ejemplo, elementos como un árbol , una lista vinculada , una tabla hash y una matriz se pueden recorrer (y modificar) utilizando un objeto Iterator .
La iteración a través de los elementos la realiza el objeto iterador, no la colección en sí. Esto simplifica la interfaz y la implementación de la colección y promueve una separación más lógica de las preocupaciones .
Una característica de un iterador completamente implementado es que el código que usa el iterador puede no saber nada sobre el tipo de agregado iterado.
Por supuesto, (en C++) casi cualquier agregado se puede iterar con un puntero void*, pero:
- no está claro cuál es el valor de "final del agregado", para una lista doblemente enlazada es &ListHead, para una matriz es &array[tamaño], para una lista enlazada individualmente es NULL
- La operación Siguiente depende en gran medida del tipo de agregado.
Los iteradores le permiten abstraer el tipo y el terminador de un agregado utilizando el polimórfico Siguiente (a menudo implementado como operator++ en C++) y el polimórfico agregado.end() que devuelve "final del agregado".
Por lo tanto, se hace posible trabajar con rangos de iteradores, en ausencia de conocimiento sobre el tipo de agregado iterado. Por ejemplo:
Iterador itBegin = agregado . comenzar ();
Iterador itEnd = agregado . fin ();
func ( comienzo , fin );
Y además:
función vacía ( Iterador itBegin , Iterator itEnd )
{
for ( Iterador it = itBegin , it != itEnd ; ++ it )
{
}
}
Ejemplos
C#
Texto fuente en
C#
/*
código de ejemplo en C#
Este código estructural demuestra el patrón Iterator que proporciona una forma de recorrer (iterar) una colección de elementos sin detallar la estructura subyacente de la colección.
*/
ocultar codigo
// Patrón de iterador -- Ejemplo estructural
utilizando el sistema ;
utilizando System.Collections ;
espacio de nombres DoFactory.GangOfFour.Iterator.Structural
{
/// <summary>
/// Clase de inicio de MainApp para Structural
/// Iterator Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Punto de entrada a la aplicación de consola.
/// </summary>
static void Main ()
{
ConcreteAggregate a = new ConcreteAggregate ();
a [ 0 ] = "Artículo A" ;
a [ 1 ] = "Artículo B" ;
a [ 2 ] = "Artículo C" ;
a [ 3 ] = "Artículo D" ;
// Crear Iterator y proporcionar
ConcreteIterator agregado i = new ConcreteIterator ( a );
consola _ WriteLine ( "Iterando sobre la colección:" );
elemento de objeto = i . primero ();
while (! i . IsDone ())
{
Console . WriteLine ( elemento );
elemento = yo . siguiente ();
}
// Esperar a la
Consola del usuario . Clave de lectura ();
}
}
/// <summary>
/// La clase abstracta 'Agregado'
/// </summary>
abstract class Aggregate
{
public abstract Iterator CreateIterator ();
public abstract int Cuenta { get ; conjunto protegido ; } objeto público abstracto este [ int index ] { get ; conjunto ; } }
/// <summary>
/// La clase 'ConcreteAggregate'
/// </summary>
class ConcreteAggregate : Aggregate
{
private readonly ArrayList _items = new ArrayList ();
public override Iterator CreateIterator ()
{
return new ConcreteIterator ( this );
}
// Obtiene el recuento de elementos
public override int Count
{
get { return _items . contar ; }
conjunto protegido { } }
// Indexador
public override object this [ int index ]
{
get { return _items [ index ]; }
establecer { _elementos . insertar ( índice , valor ); }
}
}
/// <summary>
/// La clase abstracta 'Iterator'
/// </summary>
abstract class Iterator
{
public abstract object First ();
objeto abstracto público Siguiente (); public abstract bool IsDone (); objeto abstracto público CurrentItem (); }
/// <summary>
/// La clase 'ConcreteIterator'
/// </summary>
class ConcreteIterator : Iterator
{
private readonly Aggregate _aggregate ;
privado int_actual ; _
// Constructor
público ConcreteIterator ( agregado agregado )
{
este . _agregado = agregado ;
}
// Obtiene el primer elemento de iteración
public override object First ()
{
return _aggregate [ 0 ];
}
// Obtiene el siguiente elemento de iteración
public override object Next ()
{
object ret = null ;
_actual ++;
if ( _actual < _agregado . Cuenta )
{
ret = _agregado [ _actual ];
}
volver ret ;
}
// Obtiene el elemento de iteración actual
public override object CurrentItem ()
{
return _aggregate [ _current ];
}
// Obtiene si las iteraciones están completas
public override bool IsDone ()
{
return _current >= _aggregate . contar ;
}
}
}
Salida
Iterando sobre la colección :
Artículo A
Artículo B
Artículo C
Artículo D
PHP5
código fuente
PHP5
/**
* El patrón de iterador proporciona un mecanismo para iterar a través de los elementos de una colección sin exponer la implementación de la colección.
*
* La iteración a través de los elementos la realiza el objeto iterador, no la colección en sí.
* Esto simplifica la interfaz y la implementación de la colección, y también contribuye a una distribución más lógica de responsabilidades.
*/
namespace iterator1 {
/**
* Tener una interfaz común es conveniente para el cliente porque el cliente está desacoplado de la implementación de la colección de objetos.
*
* ConcreteAggregate contiene una colección de objetos e implementa un método que devuelve un iterador para esta colección.
*/
interface IAggregate
{
/**
* Cada tipo de ConcreteAggregate es responsable de crear una instancia de Concrete Iterator que
* puede usarse para iterar sobre su colección de objetos.
*/
función pública createIterator (); }
/**
* Todos los iteradores deben implementar la interfaz Iterator.
*
* ConcreteIterator es responsable de administrar la posición de iteración actual.
*/
interface IIterator
{
/**
* @abstract
* @return boolean hay un siguiente elemento en la colección
*/
public function hasNext ();
/**
* @abstract
* @return mixto siguiente elemento de matriz
*/
función pública siguiente ();
/**
* Elimina el elemento actual de la colección
* @abstract
* @return void
*/
public function remove ();
}
/**
* En mi ejemplo, ambas colecciones usan el mismo iterador: un iterador de matriz.
*/
class ConcreteAggregate1 implementa 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 );
}
}
clase ConcreteAggregate2 implementa 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 implements IIterator
{
/**
* @var Item[] $items
*/
protected $items = array ();
/**
* @var int $posición almacena la posición de iteración actual en el arreglo
*/
public $posición = 0 ;
/**
* @param $items matriz de objetos para iterar
*/
public function __construct ( $items )
{
$this -> items = $items ;
}
public function hasNext ()
{
if ( $this -> position >= count ( $this -> items ) || count ( $this -> items ) == 0 ) {
return ( false );
} más {
retorno ( verdadero );
}
}
public function next ()
{
$menuItem = $this -> items [ $this -> position ];
$esto -> posición ++ ;
return ( $menuItem );
}
public function remove ()
{
if ( $this -> position <= 0 ) {
throw new \Exception ( 'No puede llamar a remove antes de que se haya llamado al menos a next()' );
}
if ( $esto -> artículos [ $esto -> posición - 1 ] != nulo ) {
for ( $i = $esto -> posición - 1 ; $i < cuenta ( $esto -> artículos ); $i + + ) {
$esto -> elementos [ $i ] = $esto -> elementos [ $i + 1 ];
}
$esto -> elementos [ cuenta ( $esto -> elementos ) - 1 ] = nulo ;
}
}
}
clase Cliente
{
/**
* @var ConcreteAggregate1 $agregado1
*/
public $agregado1 ;
/**
* @var ConcreteAggregate2 $agregado2
*/
public $agregado2 ;
public function __construct ( $agregado1 , $agregado2 )
{
$esto -> agregado1 = $agregado1 ;
$esto -> agregado2 = $agregado2 ;
}
public function printAggregatesItems ()
{
$iterator1 = $this -> agregado1 -> createIterator ();
echo " \ nPrimero" ;
$this -> printIteratorItems ( $ iterator1 );
$iterador2 = $esto -> agregado2 -> createIterator ();
echo " \n\ nSegundo" ;
$this -> printIteratorItems ( $ iterator2 );
}
/**
* @param $iterator IIterator
*/
función privada printIteratorItems ( $ iterator ) { while ( $ iterator -> hasNext ()) { $item = $iterator -> next (); echo " \n $artículo->nombre $artículo->precio $artículo->descripción " ; } } }
elemento
de clase {
public $ precio ;
público $nombre ;
public $descripción ;
public function __construct ( $nombre , $precio , $descripción = '' )
{
$esto -> nombre = $nombre ;
$esto -> precio = $precio ;
$esto -> descripción = $descripción ;
}
}
$corredor = nuevo Cliente ( new ConcreteAggregate1 (), new ConcreteAggregate2 ());
$corredor -> imprimirAggregatesItems ();
}
Ejemplo de iterador de constructor de PHP5
Código fuente del iterador del constructor PHP5
/**
* Patrón Composer con iterador externo
* El iterador usa la recursividad para recorrer el árbol de elementos
*/
namespace compositeIterator {
/**
* El cliente usa la interfaz AComponent para trabajar con objetos.
* La interfaz AComponent define la interfaz para todos los componentes: tanto combinaciones como nodos hoja.
* AComponent puede implementar el comportamiento predeterminado para add() remove() getChild() y otras operaciones
*/
clase abstracta AComponent {
public $nombrePropiedadPersonalizada ;
public $customPropertyDescription ;
/**
* @param AComponent $componente
*/
public function add ( $componente )
{
throw new \Exception ( "Operación no admitida" );
}
/**
* @param AComponent $componente
*/
public function remove ( $componente )
{
throw new \Exception ( "Operación no admitida" );
}
/**
* @param int $int
*/
public function getChild ( $int )
{
throw new \Exception ( "Operación no admitida" );
}
/**
* @return IPhpLikeIterator
*/
función abstracta createIterator ();
public function operation1 ()
{
throw new \Exception ( "Operación no admitida" );
}
}
/**
* Leaf hereda los métodos add() remove() getChild(, que pueden no tener sentido para un nodo hoja.
* Aunque un nodo hoja puede considerarse un nodo con cero hijos
*
* Leaf define el comportamiento de los elementos de una combinación Para hacer esto, implementa las operaciones compatibles con Composite interface
*/
class Leaf extends AComponent
{
public function __construct ( $name , $description = '' )
{
$this -> customPropertyName = $name ;
$this -> customPropertyDescription = $descripción ;
}
public function createIterator ()
{
return new NullIterator ();
}
public function operation1 ()
{
echo ( " \n Soy hoja { $this -> customPropertyName } , no quiero hacer la operación 1. { $this -> customPropertyDescription } " );
}
}
clase NullIterator implementa IPhpLikeIterator
{
public function valid ()
{
return ( false );
}
función pública siguiente ()
{
retorno ( falso );
}
public function actual ()
{
return ( null );
}
public function remove ()
{
throw new \CException ( 'operación no admitida' );
}
}
/**
* La interfaz Composite define el comportamiento de los componentes que tienen hijos y proporciona almacenamiento para ellos.
*
* El Composite también implementa operaciones relacionadas con Leaf. Algunos de ellos no pueden dejar de tener sentido para las combinaciones; en tales casos, se lanza una excepción.
*/
class Composite extiende AComponent
{
privado $_iterador = nulo ;
/**
* @var \ArrayObject AComponent[] $componentes para almacenar hijos de tipo AComponent
*/
public $componentes = null ;
public function __construct ( $name , $description = '' )
{
$this -> customPropertyName = $name ;
$this -> customPropertyDescription = $description ;
}
/**
* @param AComponent $componente
*/
public function add ( $componente )
{
if ( is_null ( $this -> components )) {
$this -> components = new \ArrayObject ;
}
$esto -> componentes -> agregar ( $componente );
}
public function remove ( $componente )
{
foreach ( $this -> components as $i => $c ) {
if ( $c === $component ) {
unset ( $this -> components [ $i ]);
}
}
}
public function getChild ( $int )
{
return ( $this -> components [ $int ]);
}
public function operation1 ()
{
echo " \n\n $this->customPropertyName $this->customPropertyDescription " ; echo " \n --------------------------------" ;
$iterador = $esto -> componentes -> getIterator ();
while ( $iterador -> válido ()) {
$componente = $iterador -> actual ();
$componente -> operación1 ();
$iterador -> siguiente ();
}
}
/**
* @return CompositeIterator
*/
public function createIterator ()
{
if ( is_null ( $this -> _iterator )) {
$this -> _iterator = new CompositeIterator ( $this -> components -> getIterator ());
}
retorno ( $esto -> _iterador );
}
}
/**
* Iterador compuesto recursivo
*/
class CompositeIterator implementa IPhpLikeIterator
{
público $ pila = matriz ();
/**
* @param \ArrayIterator $componentsIterator
*/
public function __construct ( $componentsIterator )
{
//$this->stack= new \ArrayObject;
$this -> stack [] = $componentsIterator ;
}
public function remove ()
{
throw new \CException ( 'operación no admitida' );
}
public function valid ()
{
if ( vacío ( $this -> stack )) {
return ( false );
} else {
/** @var $componentsIterator \ArrayIterator */
// obtener el primer elemento
$componentsIterator = array_shift ( array_values ( $this -> stack ));
if ( $componentsIterator -> valid ()) {
return ( true );
} else {
array_shift ( $this -> stack );
return ( $esto -> valido ());
}
}
}
public function next ()
{
/** @var $componentsIterator \ArrayIterator */
$componentsIterator = actual ( $this -> stack );
$componente = $componentesIterador -> actual ();
if ( $componente instancia de Composite ) {
array_push ( $this -> stack , $componente -> createIterator ());
}
$componentesIterador -> siguiente ();
//retorno($componente);
}
public function current ()
{
if ( $this -> valid ()) {
/** @var $componentsIterator \ArrayIterator */
// obtener el primer elemento
$componentsIterator = array_shift ( array_values ( $this -> stack )) ;
return ( $componentesIterator -> actual ());
} más {
retorno ( nulo );
}
}
}
/**
* Todos los iteradores deben implementar la interfaz Iterator.
* Esta interfaz es parte de la interfaz del iterador php estándar.
* Un iterador particular es responsable de administrar la posición de iteración actual en una colección particular.
*/
interface IPhpLikeIterator
{
/**
* @abstract
* @return boolean es el elemento actual
*/
public function valid ();
/**
* @abstract
* @return mixto mueve el cursor más lejos
*/
función pública siguiente ();
/**
* @abstract
* @return mixed obtiene el elemento actual
*/
public function current ();
/**
* elimina el elemento actual de la colección
* @abstract
* @return void
*/
public function remove ();
}
clase Cliente
{
/**
* @varAComponent
*/
public $topItem ;
public function __construct ( $topItem )
{
$this -> topItem = $topItem ;
}
public function printOperation1 ()
{
$this -> topItem -> operation1 ();
}
public function printOperation2 ()
{
echo " \n\n\n " ;
$iterador = $esto -> topItem -> createIterator ();
while ( $iterador -> válido ()) {
/** @var $componente AComponente */
$componente = $iterador -> actual ();
if ( strstr ( $component -> customPropertyName , 'leaf1' )) {
echo ( " \n Soy cliente, encontré leaf { $component -> customPropertyName } , lo dejaré aquí (para mi 'primera- colección de té de leafs). { $componente -> customPropertyDescription } " );
}
$iterador -> siguiente ();
}
}
}
prueba de
clase {
función estática pública ir () { $a = nuevo compuesto ( "c1" ); $b = nuevo compuesto ( "c2" ); $c = nuevo compuesto ( "c3" );
$topItem = nuevo compuesto ( "elemento superior" );
$elementosuperior -> agregar ( $a );
$elemento superior -> agregar ( $b );
$elementosuperior -> agregar ( $c );
$a -> agregar ( nueva Hoja ( "c1-hoja1" ));
$a -> agregar ( nueva Hoja ( "c1-hoja2" ));
$b -> agregar ( hoja nueva ( "c2-hoja1" )); $b -> agregar ( nueva Hoja ( "c2-hoja2" )); $b -> agregar ( hoja nueva ( "c2-hoja3" ));
$c -> agregar ( hoja nueva ( "c3-hoja1" )); $c -> agregar ( hoja nueva ( "c3-hoja2" ));
$cliente = nuevo Cliente ( $topItem );
$cliente -> imprimirOperacion1 ();
$cliente -> printOperation2 ();
}
}
prueba :: ir ();
}
Pitón
Código fuente en
Python
de abc import ABCMeta , método abstracto
Iterador de clase ( metaclase = ABCMeta ):
""" Iterador
abstracto
"""
_error = Ninguno # la clase del error que se arroja si la colección está fuera de los límites
def __init__ ( self , colección , cursor ):
"""
Constructor.
:param colección: la colección a recorrer por el iterador :param cursor: la posición inicial del cursor en la colección (clave)
"""
self ._collection = colección self ._cursor = cursor
@abstractmethod
def current ( self ):
"""
Devuelve el elemento actual al que apunta el iterador
"""
pasar
@abstractmethod
def next ( self ):
"""
Mueva el cursor al siguiente elemento de la colección y devuélvalo
"""
pase
@abstractmethod
def has_next ( self ):
"""
Comprobar si existe el siguiente elemento de la colección
"""
pasar
@abstractmethod
def remove ( self ):
"""
Elimina el elemento actual de la colección al que apunta el cursor
"""
pasar
def _raise_key_exception ( self ):
"""
Levantar un índice inválido contenido en el cursor
"""
levantarse a sí mismo . _error ( 'La colección de clase {} no tiene la clave " {} "' . format (
self . __class__ . __name__ , self . _cursor ))
class ListIterator ( Iterator ):
"""
Un iterador que itera sobre una lista normal
"""
_error = error de índice
def __init__ ( self , colección : lista ):
super () . __init__ ( colección , 0 )
def actual ( auto ):
si auto . _cursor < len ( self . _collection ):
return self . _colección [ auto . _cursor ]
yo mismo . _raise_key_exception ()
def siguiente ( auto ):
si len ( auto . _colección ) >= auto . _cursor + 1 :
uno mismo . _cursor += 1
volver auto . _colección [ auto . _cursor ]
yo mismo . _raise_key_exception ()
def has_next ( self ):
return len ( self . _collection ) >= self . _cursor + 1
def eliminar ( auto ):
si 0 <= auto . _cursor < len ( self . _colección ):
self . _colección _ remove ( self . _colección [ self . _cursor ])
else :
self . _raise_key_exception ()
class DictIterator ( Iterator ):
""" Iterador
de diccionario: debido al hecho de que los diccionarios en Python se implementan
como tablas hash, el orden de recorrido puede cambiar durante diferentes ejecuciones
"""
_error = Error de clave
def __init__ ( self , colección : dict ):
super () . __init__ ( colección , siguiente ( iter ( colección )))
self . _keys = lista ( self . _colección . keys ())
self . _llaves . popular ( 0 )
def actual ( auto ):
si auto . _cursor en uno mismo . _colección :
devuelve uno mismo . _colección [ auto . _cursor ]
yo mismo . _raise_key_exception ()
def siguiente ( self ):
if len ( self . _keys ):
self . _cursor = uno mismo . _llaves . pop ( 0 )
devuelve uno mismo . _colección [ auto . _cursor ]
else :
self . _raise_key_exception ()
def has_next ( self ):
return len ( self . _keys ) > 0
def eliminar ( auto ):
si auto . _cursor en uno mismo . _colección :
del self . _colección [ auto . _cursor ]
prueba :
self . next ()
excepto self . _error :
aumentar KeyError ( 'La colección de tipo {} está vacía' . format ( self . __class__ . __name__ ))
else :
self . _raise_key_exception ()
Colección de clases ( metaclase = ABCMeta ):
"""
Colección abstracta
"""
@abstractmethod
def iterator ( self ):
pase
clase ListCollection ( Colección ):
"""
Una colección contenedora para una lista normal
"""
def __init__ ( self , colección : lista ):
self . _colección = colección
def iterador ( auto ):
devuelve ListIterator ( auto . _colección )
class DictCollection ( Colección ):
"""
Colección contenedora para el diccionario
"""
def __init__ ( self , colección : dict ):
self . _colección = colección
def iterador ( auto ):
devuelve DictIterator ( auto . _colección )
def prueba ( título = str , colección = Colección ):
imprimir ( " \n {} \n " . formato ( título ))
iterador = colección . iterador ()
print ( iterador . actual ())
iterador . siguiente ()
print ( iterador . siguiente ())
iterador . eliminar ()
imprimir ( iterador . actual ())
imprimir ( iterador . tiene_siguiente ())
imprimir ()
if __name__ == '__main__' :
print ( 'OUTPUT:' )
test ( 'List testing' , ListCollection ([ 1 , 2 , 3 , 4 , 5 ]))
test ( 'Dictionary testing' , DictCollection ({ 'a' : 1 , 'b' : 2 , 'c' : 3 , 'f' : 8 }))
'''
SALIDA:
Lista de pruebas
1
3
4
Verdadero
Prueba de diccionario
1
3
2
Falso
'''
Óxido
ejemplo
de óxido
#[derivar(Depurar, Clonar, Copiar)]
pub struct ExampleRange
{
comenzar :
i64 ,
corriente :
i64 ,
fin :
i64 ,
}
impl EjemploRango
{
pub fn nuevo ( inicio :
i64 , final :
i64 ) ->
Self
{
EjemploRango
{
comenzar ,
actual :
empezar ,
fin ,
}
}
pub fn iter ( & self ) ->
EjemploRango
{
* uno mismo
}
}
usar std ::
fmt ;
impl fmt ::
Mostrar para ExampleRange
{
fn fmt ( & self , f :
& mut fmt ::
Formateador <' _ > ) ->
fmt ::
Resultado
{
¡escribe! ( f , "{}" , self . actual )
}
}
iterador impl para ExampleRange
{
tipoItem = i64 ; _
fn siguiente ( & mut self ) ->
Opción < Self ::
Item >
{
si uno mismo . actual < uno mismo . final
{
( Algunos ( auto . actual ), auto . actual += 1 ). 0
}
más
{
Ninguna
}
}
fn last ( mut self ) ->
Opción < Self ::
Item >
{
si uno mismo . actual > yo . empezar
{
( self . actual -= 1 , Some ( self . current )). una
}
más
{
Ninguna
}
}
}
fn principal ()
{
let it = ExampleRange ::
new ( 0 , 6 );
para el artículo en él
{
imprimir! ( "{}" , elemento );
}
}
'''
SALIDA :
0
una
2
3
cuatro
5
'''