Patrón Iterator
Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 56 de 61.
El patrón Iterator proporciona una forma de acceder a los elementos de una colección de manera secuencial sin exponer su estructura subyacente. En lugar de dar a los usuarios acceso directo a un array, se les proporciona un objeto que sabe cómo recorrer los datos de elemento en elemento.
Un iterador normalmente necesita dos piezas de información: una referencia a la colección y la posición actual. En C, creamos un struct para mantener este estado:
typedef struct {
int* data; // puntero al arreglo
int size; // número total de elementos
int current; // posición actual
} IntIterator;El iterador expone dos funciones clave. has_next() comprueba si hay más elementos para leer, y next() devuelve el elemento actual y avanza la posición:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}El uso del iterador se ve limpio y oculta los detalles del array:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}El llamador nunca necesita saber que numbers es un array o cómo funciona la indexación. Esta abstracción facilita el cambio de la estructura de datos subyacente más adelante — de un array a una lista enlazada, por ejemplo — sin cambiar el código que utiliza el iterador.
Desafío
FácilVamos a construir un iterador NumberList — una abstracción limpia que te permite recorrer una colección de enteros sin exponer la estructura del arreglo subyacente.
Organizarás tu código en tres archivos:
iterator.h: Define una estructuraIntIteratorque contenga un puntero a un arreglo de enteros, el tamaño total de la colección y la posición actual. Declara tres funciones:create_iterator(toma un puntero al arreglo y el tamaño, devuelve un iterador inicializado),has_next(verifica si quedan más elementos) ynext(devuelve el elemento actual y avanza la posición). ¡No olvides los include guards!iterator.c: Implementa las funciones de tu iterador. La funcióncreate_iteratordebe devolver unIntIteratorpor valor con la posición actual establecida en 0. La funciónhas_nextdevuelve 1 si hay más elementos por leer, 0 en caso contrario. La funciónnextdevuelve el elemento en la posición actual y luego incrementa la posición.main.c: Lee el número de elementos, luego lee cada valor entero en un arreglo. Crea un iterador para este arreglo, luego usa un bucle while conhas_nextynextpara recorrer e imprimir cada elemento en su propia línea.
Tu programa recibirá:
- El número de elementos en el arreglo
- Cada valor entero en una línea separada
¡Usa el patrón iterador para imprimir todos los elementos — nada de indexación directa del arreglo en tu bucle de recorrido!
Ejemplo de salida cuando las entradas son 4, luego 10, 20, 30, 40:
10
20
30
40Ejemplo de salida cuando las entradas son 3, luego -5, 0, 100:
-5
0
100Ejemplo de salida cuando las entradas son 1, luego 42:
42El iterador oculta cómo se almacenan los datos — tu bucle principal simplemente pregunta "¿hay más?" y "dame el siguiente" sin saber nada sobre los índices del arreglo o el diseño de la memoria.
Hoja de referencia
El patrón Iterator proporciona una forma de acceder a los elementos de una colección de manera secuencial sin exponer su estructura subyacente.
Una estructura de iterador contiene la referencia a la colección, el tamaño y la posición actual:
typedef struct {
int* data; // pointer to the array
int size; // total number of elements
int current; // current position
} IntIterator;El iterador expone dos funciones clave:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}El uso del iterador oculta los detalles de implementación del array:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}Esta abstracción permite cambiar la estructura de datos subyacente sin modificar el código del cliente.
Pruébalo tú mismo
#include <stdio.h>
#include "iterator.h"
int main() {
int n;
scanf("%d", &n);
int arr[n];
// TODO: Leer n valores enteros en el arreglo
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// TODO: Crear un iterador para el arreglo
// TODO: Usar un bucle while con has_next y next para recorrer
// e imprimir cada elemento en su propia línea
// ¡NO uses indexación directa del arreglo en tu bucle de recorrido!
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculo