Intención del patrón
- Proporciona una manera de acceder a los elementos de un objeto contenedor (colección) de manera secuencial sin exponer su representación subyacente.
- La librería estándar de C++ y Java tienen abstracciones que permiten desacoplar las colecciones de los algoritmos.
- Promueve al "estado completo del objeto" del recorrido de una colección.
- Recorrido polimórfico.
Ejemplo de problema
Necesidad de abstraer el recorrido de muy diferentes estructuras de datos para que los algoritmos puedan ser capaces de interactuar con cada una de forma transparente.Discusión
Una colección como puede ser una lista, debería proporcionar una manera de acceder a sus elementos sin exponer su estructura interna. Más aun, se debería poder recorrer la lista de diferentes maneras dependiendo de lo que se necesita. Pero es probable que no se quiera inflar la interfaz con operaciones para las diferentes formas de recorrerla, inclusive si se pudiera anticipar a las que se requieren. Y, proporcionando una interfaz uniforme para recorrer muchos tipos de colección (es decir, una iteración polimórfica) puede ser útil.El patrón Iterator permite realizar esto. La idea puntual es tomar la responsabilidad del acceso y recorrido de la colección y colocarla dentro de un objeto Iterator que defina el protocolo estándar para recorrer.
La abstracción de Iterator es fundamental para una tecnología denominada "programación genérica" (Generics en C#). Esta estrategia buscar separar explicitamente la noción de "algoritmo" de la de "estructura de datos". El motivo es para: promover desarrollos basados en componentes, aumentar la productividad y reducir la administración de configuración.
Como ejemplo, si se quisiera soportar cuatro estructuras de datos (array, binary tree, linked list y hash table) y tres algoritmos (sort, find y merge), un enfoque tradicional podría requerir cuatro veces tres permutaciones a desarrollar y mantener. Considerando que, con un enfoque de programación genérica necesitaría solo cuatro más tres elementos de configuración.
Estructura
El Cliente usa directamente la interfaz pública de la clase Collection. Pero el acceso a laos elementos de la clase Collection está encapsulado detrás de un nivel adicional de abstracción llamado Iterator. Cada clase derivada de Collection conoce cuál clase derivada de Iterator crear y retornar. Después de eso, el Cliente se basa en la interfaz definida en la clase base Iterator.Ejemplo
El patrón Iterator proporciona maneras de acceder a los elementos de un objeto contenedor (colección) de manera secuencial sin exponer la estructura del objeto. Los archivos son objetos similares a las colecciones. En oficinas en donde el acceso a los archivos es hecho a través de administrativos o secretarias, el patrón Iterator es demostrado con la secretaria actuando como Iterator. Muchas comedias de televisión han sido creadas al rededor de la premisa de un ejecutivo tratando de entender el sistema de archivado de su secretaria. Para el ejecutivo, dicho sistema es confuso e ilógico, pero la secretaria es capaz de acceder a los archivos rápida y eficientemente.En viejos aparatos de televisión, un dial era utilizado para cambiar los canales. Para realizar zapping, el televidente debía girar dicho dial a través de cada posición que representaba un canal, independientemente de si ese canal tenía o no señal. En los aparatos modernos, se utilizan los botones siguiente y previo. Cuando un televidente presiona el botón siguiente, se muestra al siguiente canal sintonizado. Consideremos estar mirando televisión en la habitación de un hotel en una ciudad desconocida. Al navegar por los canales, el número del canal no es importante, pero el programa sí lo es. Si el programa de un canal no resulta interesante, el televidente puede solicitar el siguiente canal, sin conocer el número.
Check list
- Agregar un método
Create_Iterator()
a la clase Collection y garantizar el acceso a la clase Iterator. - Diseñar una clase Iterator que pueda encapsular el recorrido de los elementos de la clase Collection.
- Los clientes piden a al objeto Collection crear un objeto Iterator.
- Los clientes usan los protocolos
first()
,is_done()
,next()
ycurrent_item()
para acceder a los elementos de la clase Collection.
Reglas de oro
- El árbol abstracto de sintaxis de Iterpreter es un Composite (también Visitor e Iterator son aplicables.
- Iterator puede recorrer un Composite. Visitor puede aplicar una operación sobre un Composite.
- Iteretaros polimórficos descansan la responsabilidad de instanciar la subclase apropiada de Iterator apropiada en Factory methods.
- Memento es a menudo usado en conjunto con Iterator. Iterator puede usar a Memento para capturar el estado de una iteración. El Iterator almacena el Memento internamente.
Ejemplo de código en C#
using System;
using System.Collections;
class MainApp
{
static void Main()
{
ConcreteAggregate a = new ConcreteAggregate();
a[0] = "Item A";
a[1] = "Item B";
a[2] = "Item C";
a[3] = "Item D";
// Create Iterator and provide aggregate
ConcreteIterator i = new ConcreteIterator(a);
Console.WriteLine("Iterating over collection:");
object item = i.First();
while (item != null)
{
Console.WriteLine(item);
item = i.Next();
}
// Wait for user
Console.Read();
}
}
// "Aggregate"
abstract class Aggregate
{
public abstract Iterator CreateIterator();
}
// "ConcreteAggregate"
class ConcreteAggregate : Aggregate
{
private ArrayList items = new ArrayList();
public override Iterator CreateIterator()
{
return new ConcreteIterator(this);
}
// Property
public int Count
{
get{ return items.Count; }
}
// Indexer
public object this[int index]
{
get{ return items[index]; }
set{ items.Insert(index, value); }
}
}
// "Iterator"
abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
// "ConcreteIterator"
class ConcreteIterator : Iterator
{
private ConcreteAggregate aggregate;
private int current = 0;
// Constructor
public ConcreteIterator(ConcreteAggregate aggregate)
{
this.aggregate = aggregate;
}
public override object First()
{
return aggregate[0];
}
public override object Next()
{
object ret = null;
if (current < aggregate.Count - 1)
{
ret = aggregate[++current];
}
return ret;
}
public override object CurrentItem()
{
return aggregate[current];
}
public override bool IsDone()
{
return current >= aggregate.Count ? true : false ;
}
}
2 comentarios:
Muy bueno, gracias
Me alegra que te haya gustado.
Publicar un comentario
Muchas gracias por leer el post y comentarlo.