Iterador

RECU-0193 (Recurso Patrón)

Descripción

Es un patrón define una interfaz que declara los métodos necesarios para acceder secuencialmente a un grupo de objetos de una colección.

Nombre

También conocido como Iterator, Cursor.

Clasificación

Patrón de comportamiento

Motivación

Debemos de disponer de un medio para navegar por los datos de una lista sin exponer su estructura interna. Asi mismo, se debe recorrer la lista de varias maneras pero sin que esto signifique añadir operaciones a la lista por cada tipo de recorrido. En algunos casos nos interesa mantener varios recorridos simultáneamente.

El patrón Iterador permite hacer todo esto. La solución que propone es dar la responsabilidad de recorre la lista a un objeto Iterador. Este define una interfaz para acceder a los elementos de la lista.

Aplicabilidad

  • Para acceder a la información de un agregado sin exponer su estructura interna.
  • Se quiere permitir varios tipo de recorrido sobre un agregado.
  • Proporcionar una interfaz uniforme para recorrer diferentes tipos de agregados.

Estructura

La estructura gráfica del patrón es la siguiente:

Participantes

  • Agregado: define la interfaz para crear un objeto Iterador.
  • Iterador: define la interfaz para agregar y recorrer elementos.
  • AgregadoConcreto: Implementa la interfaz para crear un objeto Iterador.
  • IteradorConcreto: Implementa la interfaz de Iterador y mantiene la posición actual del recorrido.

Colaboraciones

Un IteradorConcreto guarda como pasa el objeto actual al siguiente del agregado.

Consecuencias

  • Permite variaciones en el recorrido de un Agregado. Nuevos recorridos simplemente necesitan nuevas subclases de Iterador, si es una modificación solo es necesario cambiar la instancia de Iterador concreta
  • Puede hacerse más de un recorrido a la vez sobre un Agregado.
  • Los Iteradores simplifican la interfaz del contenedor

Implementación

Para una correcta implementación del patrón deben considerase las siguientes cuestiones:

  • ¿Quién controla la iteración? Puede realizarse de forma externa a través del cliente o realizarlo de forma interna con el Iterador. En este caso, el Iterador recibe una función a aplicar sobre los elementos del Agregado y el recorrido es automático.
  • ¿Quién define el algoritmo de recorrido? Se puede hacer en el Iterador o en el Agregado. Si es en el caso del Agregado, se implementa el método siguiente y se deja el Iterador para almacenar la posición actual. En el caso de realizarlo en el Iterador, los recorridos son más fáciles de implementar pero se compromete la encapsulación.
  • ¿Cómo de robusto es el Iterador? Es recomendable formalizar un Iterador robusto que permita inserciones y borrados sin alterar el recorrido.
  • Se pueden añadir operaciones adicionales al Iterador.
  • Iteradores Nulos: Ayudan a manejar condiciones límite. El método Terminado() devuelve siempre True. Útil para estructuras heterogéneas

Código de ejemplo

import java.util.*;
class IntSet {
   private Hashtable ht = new Hashtable();
// 1. Diseñamosun iterador interno
   public static class Iterador {
      private IntSet      set;
      private Enumeracion e;
      private Integer     actual;
      public Iterador( IntSet in ) { set = in; }
      public void    primero()       { e = set.ht.keys();  next(); }
      public boolean realizado()      { return actual == null; }
      public int     valorActual() { return actual.intValue(); }
      public void    next()        {
         try { actual = (Integer) e.nextElement(); }
         catch (NoSuchElementException e) { actual = null; }
   }  }
public void      add( int in )     { ht.put( new Integer( in ), "null" ); }
   public boolean   esMiembro( int i ) { return ht.containsKey(new Integer(i)); }
   public Hashtable getHashtable()    { return ht; }
// 2. Añadir un IteradorConcreto()
   public Iterador  crearIterador()  { return new Iterador( this ); }
}
class IteradorDemo {
   public static void main( String args ) {
      IntSet set = new IntSet();
      for (int i=2; i < 10; i += 2) set.add( i );
      for (int i=1; i < 9; i++)
         System.out.print( i + "-" + set.esMiembro( i ) + "  " );
  // Cliente va creando objetos iteradores
      IntSet.Iterador it1 = set.crearIterador();
      IntSet.Iterador it2 = set.crearIterador();
      System.out.print( "\nIterator:    " );
      for ( it1.primero(), it2.primero();  ! it1.realizado();  it1.next(), it2.next() )
         System.out.print( it1.valorActual() + " " + it2.valorActual() + "  " );
// Java usa una collecion propia que la llammamos enumeracion
      System.out.print( "\nEnumeracion: " );
      for (Enumeration e = set.getHashtable().keys(); e.hasMoreElements(); )
         System.out.print( e.nextElement() + "  " );
      System.out.println();
  } 
}

La salida sería:

1-false  2-true  3-false  4-true  5-false  6-true  7-false  8-true
Iterador:    8 8  6 6  4 4  2 2
Enumeracion: 8  6  4  2

Usos conocidos

Es muy utilizado en Java. En java.util.iterator

Patrones relacionados

  • Composite: Iterador es a menudo utilizado como estructuras recursivas en Composites.
  • Memento: Es utilizado a menudo Memento para capturar el estado de una iteración.

Contenidos relacionados

Recursos
Área: Desarrollo » Patrones de Diseño
Código Título Tipo Carácter
RECU-0013 Patrones de diseño Ficha Recomendado
RECU-0184 Composite Patrón Recomendado
RECU-0195 Memento Patrón Recomendado