Menu
Coddy logo textTech

Patrón Iterador

Parte de la sección Programación Orientada a Objetos del Journey de Lua de Coddy. Lección 64 de 70.

Cuando tienes una colección de elementos almacenada dentro de un objeto, a menudo quieres recorrerlos. El for genérico de Lua funciona perfectamente con iteradores personalizados, y puedes incorporar esta funcionalidad directamente en tus clases.

El patrón Iterator permite que un objeto controle cómo se recorren sus datos internos. Un enfoque elegante utiliza el método metamágico __call, que hace que un objeto se pueda invocar como una función. Cada llamada devuelve el siguiente elemento hasta que no quedan más.

local Collection = {}
Collection.__index = Collection

function Collection:new()
    local obj = { items = {}, index = 0 }
    setmetatable(obj, Collection)
    return obj
end

function Collection:add(item)
    table.insert(self.items, item)
end

function Collection:__call()
    self.index = self.index + 1
    return self.items[self.index]
end

Con __call definido, puedes iterar usando un bucle while o pasar el objeto directamente a un for genérico:

local bag = Collection:new()
bag:add("apple")
bag:add("banana")

for item in bag do
    print(item)
end

El bucle llama a bag() repetidamente. Cuando __call devuelve nil (no quedan más elementos), el bucle se detiene. Este patrón encapsula la lógica de iteración dentro del propio objeto, lo que te da un control total sobre cómo y en qué orden se accede a los elementos.

challenge icon

Desafío

Fácil

¡Construyamos una clase Playlist que puedas recorrer mediante el bucle genérico for de Lua! Implementarás el patrón Iterador usando el metamétodo __call, lo que permitirá recorrer tu lista de reproducción canción por canción.

Organizarás tu código en dos archivos:

  • Playlist.lua: Crea una clase Playlist que almacene las canciones internamente. Tu clase necesita un constructor :new() que inicialice una lista de canciones vacía y establezca el índice de iteración en 0. Añade un método :addSong(title) para agregar canciones a la lista de reproducción. Lo más importante es implementar el metamétodo __call para que cada vez que se "llame" a la lista de reproducción, devuelva la siguiente canción de la lista (o nil cuando no haya más canciones).
  • main.lua: Requiere tu módulo Playlist y crea una nueva lista de reproducción. Añádele canciones según las entradas que recibas; después, usa un bucle genérico for para recorrer la lista de reproducción e imprimir el título de cada canción en su propia línea.

La magia del patrón Iterador consiste en que tu objeto Playlist se vuelve invocable: cuando se usa en un bucle for, Lua lo llama repetidamente hasta que devuelve nil, proporcionándote cada canción en secuencia.

Recibirás tres entradas, cada una representando el título de una canción que se añadirá a tu lista de reproducción (en orden).

Por ejemplo, si las entradas son Bohemian Rhapsody, Stairway to Heaven y Hotel California, la salida debería ser:

Bohemian Rhapsody
Stairway to Heaven
Hotel California

Si las entradas son Yesterday, Imagine y Let It Be, la salida debería ser:

Yesterday
Imagine
Let It Be

Pruébalo tú mismo

-- Requiere el módulo Playlist
local Playlist = require('Playlist')

-- Lee tres títulos de canciones de la entrada
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()

-- TODO: Crea una nueva playlist usando Playlist:new()

-- TODO: Añade las tres canciones a la playlist usando :addSong()

-- TODO: Usa un bucle for genérico para iterar a través de la playlist
-- e imprime cada título de canción en su propia línea
-- Hint: for song in playlist do ... end
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Lua online