Pattern Iterator
Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 64 di 70.
Quando hai una raccolta di elementi memorizzati all'interno di un oggetto, spesso vuoi scorrerli con un ciclo. Il ciclo generico for di Lua funziona con qualsiasi funzione iteratrice: chiama la funzione prima di ogni iterazione e si ferma quando la funzione restituisce nil.
Il pattern Iterator fornisce all’oggetto un metodo che restituisce una funzione del genere. La funzione mantiene la propria posizione in una variabile locale, quindi la posizione appartiene a un ciclo, non alla raccolta:
local Collection = {}
Collection.__index = Collection
function Collection:new()
local obj = { items = {} }
setmetatable(obj, Collection)
return obj
end
function Collection:add(item)
table.insert(self.items, item)
end
function Collection:iter()
local index = 0
return function()
index = index + 1
return self.items[index]
end
endOgni chiamata a bag:iter() crea una nuova funzione con il proprio index, che parte da 0. La funzione è una closure: può continuare a usare index e self anche dopo che iter ha restituito un valore. Dopo l’ultimo elemento, self.items[index] è nil e il ciclo si interrompe:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag:iter() do
print(item) -- apple, poi banana
end
for item in bag:iter() do
print(item) -- apple, poi di nuovo banana
endMantieni la posizione fuori dalla raccolta stessa. Se l'oggetto memorizzasse self.index e fungesse da iteratore di se stesso, il primo ciclo lascerebbe l'indice alla fine, quindi un secondo ciclo non stamperebbe nulla, mentre un ciclo interrotto in anticipo con break farebbe iniziare il ciclo successivo a metà.
Sfida
FacileCreiamo una classe Playlist che puoi scorrere con il ciclo generico for di Lua! Implementerai il pattern Iterator con un metodo :iter() che restituisce una funzione iteratore.
Organizzerai il codice in due file:
Playlist.lua: crea una classe Playlist che memorizza internamente i brani. La tua classe deve avere un costruttore:new()che inizializza un elenco di brani vuoto e un metodo:addSong(title)che vi aggiunge un brano. Soprattutto, aggiungi un metodo:iter()che restituisce una nuova funzione ogni volta che viene chiamato. Questa funzione memorizza la propria posizione in una variabile locale e restituisce il brano successivo a ogni chiamata, oppurenilquando non ci sono altri brani.main.lua: richiedi il modulo Playlist e crea una nuova playlist. Aggiungi i brani in base agli input ricevuti, poi usa un ciclo genericoforsuplaylist:iter()per stampare il titolo di ogni brano su una riga separata.
Poiché ogni chiamata a :iter() inizia dal primo brano, puoi scorrere la stessa playlist un numero qualsiasi di volte.
Riceverai tre input, ciascuno dei quali rappresenta il titolo di un brano da aggiungere alla playlist (nell'ordine).
Ad esempio, se gli input sono Bohemian Rhapsody, Stairway to Heaven e Hotel California, l'output dovrebbe essere:
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaSe gli input sono Yesterday, Imagine e Let It Be, l'output dovrebbe essere:
Yesterday
Imagine
Let It BeProvalo tu
-- Carica il modulo Playlist con require
local Playlist = require('Playlist')
-- Leggi tre titoli di canzoni dall'input
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()
-- TODO: Crea una nuova playlist usando Playlist:new()
-- TODO: Aggiungi le tre canzoni alla playlist usando :addSong()
-- TODO: Usa un ciclo for generico su playlist:iter()
-- e stampa il titolo di ogni canzone su una riga separata
-- Suggerimento: for song in playlist:iter() do ... end
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Il concetto di «self»
Tabelle con funzioni«self» esplicitoLa sintassi dei due puntiPunto o due puntiRiepilogo - Spostare il punto4Progetto: Banca digitale
Configurazione del progettoMetodo di deposito2Schema del prototipo di classe
Il concetto di prototipoCollegare con __indexIl costruttore :new()Inizializzare gli attributiIstanze indipendentiRiepilogo - Fabbrica di auto5Sovraccarico degli operatori nella OOP
Sommare oggettiSottrarre oggettiConcatenare oggettiConfrontare oggetti (<, >)Ripasso - Calcoli con il portafoglio8Incapsulamento
Convenzioni di denominazioneClosure per la privacyAccesso tramite closureTabelle di sola letturaLogica di convalidaRiepilogo - Cassaforte sicura11Modelli di progettazione (base)
Funzioni factoryTabella singletonPattern IteratorObserver (listener)Riepilogo - Factory per logger3Stato e comportamento degli oggetti
Variabili di istanzaMetodi getterMetodi setterProprietà calcolateFormattazione delle stringheControlli di uguaglianzaRiepilogo - Voto dello studente6Fondamenti dell'ereditarietà
Configurare l'ereditarietàEreditare i metodiEstendere il costruttoreAggiungere metodi alla classe figliaCondiviso vs specificoRiepilogo - Gerarchia delle formeEsercitati da solo: Compilatore Lua online