Patrón Iterador

 
 
Clasificación Intención Otros nombres Motivación Aplicabilidad Estructura Participantes
Colaboraciones Consecuencias Implementación Código ejemplo Usos  Patrones Relacionados  Autor
 

 

Clasificación

Patrones de Comportamiento.
 

 

Intención

Proveer una forma de tener acceso secuencial a los elementos de un objeto agregado sin tener que exponer su representación interna.
 

Otros nombres

Iterator 
Cursor
 

Motivación

Un objeto agregado, tal como una lista, debería proveer un modo de brindar acceso a sus elementos sin exponer su estructura interna. Más aún, quizás se desea recorrer la lista en diferentes formas, dependiendo de lo que Ud. quiera realizar. Pero, probablemente, la idea no es aumentar la interfaz de la lista con operaciones para recorridos diferentes, aún anticipando los que se necesitarán. Tal vez, también se necesite tener más de un recorrido en la misma lista. 

El patrón Iterator permite llenar todas estas espectativas. La idea principal en este patrón es tomar la responsabilidad del acceso y recorrido de la lista y colocarla dentro del objeto iterator. La clase Iterator define una interfaz para el acceso de los elementos de la lista. Un objeto iterador es responsable de mantener la pista del elemento actual; esto es, sabe cuáles elementos ya han sido recorridos. 

Separar el mecanismo de recorrido del objeto List nos permite definir iteradores para diferentes políticas de recorrido sin tener que enumerarlas en la interfaz de List. Por ejemplo, FilteringListIterator puede proveer acceso solo a aquellos elementos que cumplan una política de filtro específica. 

Note que el iterador y la lista están acoplados, y el cliente debe saber que es una lista lo que se está recorriendo, en lugar de algún otra estructura agregada. De ahí que el cliente comprometa una estructura agregada particular. Sería mejor si pudiésemos cambiar la clase agregada sin cambiar el código cliente. Esto lo logramos generalizando el concepto de iterador para soportar iteración polimorfa

Definimos una clase AbstractList que provea una interfaz común para manipular listas. De igual forma, necesitamos una clase abstracta Iterator que defina una interfaz de iteración común. Luego podemos definir subclasses iteradoras concretas para las diferentes implementaciones de la lista. Como resultado, el mecanismo de iteración llega a ser independiente de las clases agregadas concretas. 

El problema restante radica en cómo crear el iterador. Ya que lo que queremos es escribir código independiente de las subclasses concretas de List, no podemos simplemente instanciar una clase específica. En su lugar, hacemos a los objetos de la lista responsables por la creación de su iterador correspondiente. Esto requiere una operación tal como CreateIterator, por medio de la cual los clientes solicitan un objeto iterador. 

 

Aplicabilidad

Utilize el patrón Iterator: 
     
  • para tener acceso a los contenidos de un objeto agregado sin tener que exponer su estructura interna.
  • para soportar múltiples recorridos de objetos agregados.
  • para proveer una interfaz uniforme para recorridos en estructuras diferentes de agregados (esto es, para soportar iteración polimorfa).

Estructura

Diagrama de Estructura Estática Diagrama de Secuencia

Participantes

  • Iterator: el cual define una interfaz para el acceso y recorrido de los elementos.
  • ConcreteIterator: el cual implementa la interfaz de Iterator y mantiene la pista de la posición actual en el recorrido del agregado.
  • Aggregate: el cual define una interfaz para la creación de un objeto Iterator.
  • ConcreteAggregate: el cual implementa la interfaz de creación de Iterator para retornar una instancia del ConcreteIterator adecuado.

Colaboraciones

Un ConcreteIterator mantiene la pista de cuál es el objeto actual en el agregado y puede calcular el objeto siguiente en el recorrido.
 

Consecuencias

Este patrón tiene tres consecuencias importantes: 
     
  1. Soporte a variaciones en el recorrido de un agregado, puesto que agregados complejos pueden requerir recorridos en muchas formas. Los iteradores hacen fácil cambiar el algoritmo de recorrido, con sólo reemplazar la instancia del iterador a una diferente.
  2. Los iteradores simplifican la interfaz de los agregados, ya que la interfaz de los recorridos se encuentra en los iteradores y no en los agregados.
  3. Más de un recorrido puede estar pendiente en un agregado, puesto que cada iterador mantiene la pista de su recorrido. Por lo tanto, se puede tener más de un recorrido en progreso al tiempo.
 

Implementaciones

Los iteradores tienen muchas variantes en la implementación y alternativas. Algunas de las más importantes son las siguientes. Las ventajas dependen de las estructuras de control que el lenguaje provea. 
     
  1. ¿Quién controla la iteración?. Referido a iteración interna (controlada por el iterador), o iteración externa (controlada por el cliente).
  2. ¿Quién define el algoritmo de recorrido?. Referido a si lo define el agregado, con lo cual el iterador es utilizado sólo como cursor de la posición actual; o si lo define el iterador.
  3. ¿Cuán robusto es el iterador?. Referido a la manera en que se aseguran las iteraciones cuándo se ha realizado un cambio (inserción y/o eliminación) en el objeto agregado.
  4. Operaciones adicionales en el iterador. Referido a la adición de operaciones a las ya básicas (First, Next, IsDone y CurrentItem).
  5. Utilización de iteradores polimorfos en C++.
  6. Iteradores con acceso privilegiado. Referido a que un iterador puede ser visto como una extensión (friend) del agregado que lo creó.
  7. Iteradores para compuestos (Composite).
  8. Iteradores nulos. Referido a un iterador útil para el manejo de condiciones de frontera.

Código ejemplo

  1. Recorrido en Pre-Orden de un Árbol Binario.
  2. Implementación de una lista con dos iteradores.
  

Usos conocidos

Los Iteradores son comunes en sistemas orientados a objetos (Smalltalk, ET++, ObjectWindows, etc.), de hecho, la mayoría de librerías de clases ofrecen iteradores en una forma u otra. 
En general, los iteradores se ofrecen junto con las estructuras de datos básicas: Listas, Colas, Pilas, etc.
 

Patrones relacionados

Composite 
Factory Method 
Memento
 
 

Autor

Tomás Puello