Introducción
El patrón de diseño Iterator es un patrón de comportamiento que proporciona una forma de acceder secuencialmente a los elementos de un objeto agregado sin exponer su representación subyacente. Este patrón es útil cuando se necesita recorrer una colección de objetos de manera uniforme, independientemente de su estructura interna.
Conceptos Clave
- Iterador: Un objeto que permite recorrer una colección de elementos.
- Colección: Un objeto que contiene múltiples elementos y puede proporcionar un iterador para recorrerlos.
- Interfaz de Iterador: Define las operaciones necesarias para recorrer la colección (por ejemplo,
next()
,hasNext()
).
Estructura del Patrón Iterator
El patrón Iterator se compone de los siguientes componentes:
- Iterador (Iterator): Define la interfaz para acceder y recorrer los elementos.
- Iterador Concreto (ConcreteIterator): Implementa la interfaz del iterador y mantiene la posición actual en la iteración.
- Colección (Aggregate): Define la interfaz para crear un iterador.
- Colección Concreta (ConcreteAggregate): Implementa la interfaz de la colección y devuelve una instancia del iterador concreto.
Diagrama UML
+-------------------+ +-------------------+ | Client | | Iterator | +-------------------+ +-------------------+ | - aggregate: List | | + hasNext(): bool | | - iterator: Iter |<----| + next(): Element | +-------------------+ +-------------------+ | ^ | | v | +-------------------+ +-------------------+ | ConcreteIterator | | Aggregate | +-------------------+ +-------------------+ | - index: int | | + createIterator()| | + hasNext(): bool | +-------------------+ | + next(): Element | ^ +-------------------+ | ^ | | | +-------------------+ +-------------------+ | ConcreteAggregate | | ConcreteAggregate | +-------------------+ +-------------------+ | - items: List | | + createIterator()| +-------------------+ +-------------------+
Ejemplo Práctico en Python
Vamos a implementar un ejemplo simple del patrón Iterator en Python. Imaginemos que tenemos una colección de números y queremos iterar sobre ellos.
Código
Interfaz del Iterador
from abc import ABC, abstractmethod class Iterator(ABC): @abstractmethod def has_next(self) -> bool: pass @abstractmethod def next(self): pass
Iterador Concreto
class NumberIterator(Iterator): def __init__(self, numbers): self._numbers = numbers self._position = 0 def has_next(self) -> bool: return self._position < len(self._numbers) def next(self): if self.has_next(): number = self._numbers[self._position] self._position += 1 return number else: raise StopIteration
Interfaz de la Colección
from abc import ABC, abstractmethod class Aggregate(ABC): @abstractmethod def create_iterator(self) -> Iterator: pass
Colección Concreta
class NumberCollection(Aggregate): def __init__(self): self._numbers = [] def add_number(self, number): self._numbers.append(number) def create_iterator(self) -> Iterator: return NumberIterator(self._numbers)
Uso del Patrón Iterator
if __name__ == "__main__": collection = NumberCollection() collection.add_number(1) collection.add_number(2) collection.add_number(3) iterator = collection.create_iterator() while iterator.has_next(): number = iterator.next() print(number)
Explicación del Código
- Interfaz del Iterador: Define los métodos
has_next()
ynext()
. - Iterador Concreto: Implementa la interfaz del iterador y mantiene la posición actual en la colección.
- Interfaz de la Colección: Define el método
create_iterator()
. - Colección Concreta: Implementa la interfaz de la colección y devuelve una instancia del iterador concreto.
- Uso del Patrón Iterator: Crea una colección de números, agrega números a la colección y usa el iterador para recorrer los números.
Ejercicio Práctico
Ejercicio
Implementa un iterador para una colección de nombres. La colección debe permitir agregar nombres y el iterador debe recorrer los nombres en orden.
Solución
class NameIterator(Iterator): def __init__(self, names): self._names = names self._position = 0 def has_next(self) -> bool: return self._position < len(self._names) def next(self): if self.has_next(): name = self._names[self._position] self._position += 1 return name else: raise StopIteration class NameCollection(Aggregate): def __init__(self): self._names = [] def add_name(self, name): self._names.append(name) def create_iterator(self) -> Iterator: return NameIterator(self._names) if __name__ == "__main__": collection = NameCollection() collection.add_name("Alice") collection.add_name("Bob") collection.add_name("Charlie") iterator = collection.create_iterator() while iterator.has_next(): name = iterator.next() print(name)
Retroalimentación
- Error Común: Olvidar incrementar la posición en el iterador. Asegúrate de incrementar
_position
después de obtener el elemento actual. - Consejo: Siempre verifica si hay más elementos antes de llamar a
next()
para evitar excepciones.
Conclusión
El patrón Iterator es una herramienta poderosa para recorrer colecciones de manera uniforme sin exponer su estructura interna. Al implementar este patrón, se puede mejorar la flexibilidad y la reutilización del código. En el siguiente tema, exploraremos el patrón Mediator, que facilita la comunicación entre objetos sin necesidad de referencias directas entre ellos.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil