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 .
iterador
iterador
Tipo de conductual
Descrito en Patrones de diseño

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:

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 '''