Wzorzec iteratora
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 64 z 70.
Gdy masz kolekcję elementów przechowywanych w obiekcie, często chcesz je przeglądać. Ogólna pętla for w Lua działa z dowolną funkcją iteratora: wywołuje tę funkcję przed każdym przebiegiem i zatrzymuje się, gdy funkcja zwróci nil.
Wzorzec Iterator daje obiektowi metodę, która zwraca taką funkcję. Funkcja przechowuje swoją pozycję w zmiennej lokalnej, więc pozycja należy do jednej pętli, a nie do kolekcji:
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
endKażde wywołanie bag:iter() tworzy nową funkcję z własnym index, którego wartość początkowa to 0. Funkcja jest domknięciem: nadal może używać index i self po zwróceniu przez iter. Po ostatnim elemencie self.items[index] ma wartość nil i pętla się zatrzymuje:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag:iter() do
print(item) -- apple, potem banana
end
for item in bag:iter() do
print(item) -- ponownie apple, potem banana
endNie przechowuj pozycji w samej kolekcji. Gdyby obiekt przechowywał self.index i był własnym iteratorem, po pierwszej pętli indeks pozostałby na końcu, więc druga pętla niczego by nie wypisała, a pętla przerwana wcześniej za pomocą break sprawiłaby, że następna pętla zaczęłaby w połowie.
Wyzwanie
ŁatwyZbudujmy klasę Playlist, po której można iterować za pomocą ogólnej pętli for w Lua! Zaimplementujesz wzorzec Iterator za pomocą metody :iter(), która zwraca funkcję iteratora.
Rozmieścisz swój kod w dwóch plikach:
Playlist.lua: Utwórz klasę Playlist, która przechowuje utwory. Klasa powinna mieć konstruktor:new(), który inicjalizuje pustą listę utworów, oraz metodę:addSong(title), która dodaje do niej utwór. Co najważniejsze, dodaj metodę:iter(), która za każdym razem, gdy zostanie wywołana, zwraca nową funkcję. Ta funkcja przechowuje swoją pozycję w zmiennej lokalnej i przy każdym wywołaniu zwraca następny utwór albonil, gdy nie ma już więcej utworów.main.lua: Załaduj moduł Playlist i utwórz nową playlistę. Dodaj do niej utwory na podstawie otrzymanych danych wejściowych, a następnie użyj ogólnej pętliforpoplaylist:iter(), aby wypisać tytuł każdego utworu w osobnym wierszu.
Ponieważ każde wywołanie :iter() rozpoczyna od pierwszego utworu, po tej samej playliście można iterować dowolną liczbę razy.
Otrzymasz trzy dane wejściowe, z których każda reprezentuje tytuł utworu do dodania do playlisty (w podanej kolejności).
Na przykład, jeśli dane wejściowe to Bohemian Rhapsody, Stairway to Heaven i Hotel California, dane wyjściowe powinny wyglądać tak:
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaJeśli dane wejściowe to Yesterday, Imagine i Let It Be, dane wyjściowe powinny wyglądać tak:
Yesterday
Imagine
Let It BeSpróbuj swoich sił
-- Załaduj moduł Playlist
local Playlist = require('Playlist')
-- Wczytaj z wejścia trzy tytuły piosenek
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()
-- TODO: Utwórz nową playlistę za pomocą Playlist:new()
-- TODO: Dodaj trzy piosenki do playlisty za pomocą :addSong()
-- TODO: Użyj ogólnej pętli for do iteracji po playlist:iter()
-- i wypisz każdy tytuł piosenki w osobnym wierszu
-- Wskazówka: for song in playlist:iter() do ... end
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Koncepcja „self”
Tabele z funkcjamiJawne „self”Składnia z dwukropkiemKropka czy dwukropekPodsumowanie — poruszający się punkt4Projekt: Bank cyfrowy
Konfiguracja projektuMetoda wpłaty7Polimorfizm i nadpisywanie
Nadpisywanie metodWywoływanie metod klasy nadrzędnejTypowanie kaczeWspólny interfejsSprawdzanie typuPodsumowanie — role pracowników10Projekt: Menedżer kształtów
Konfiguracja projektuKlasa prostokątaKlasa kołaMetoda obwoduKolekcja kształtówPole całkowiteFiltrowanie kształtów2Wzorzec prototypu klasy
Koncepcja prototypuŁączenie za pomocą __indexKonstruktor :new()Inicjalizacja atrybutówNiezależne instancjePodsumowanie – fabryka samochodów5Przeciążanie operatorów w OOP
Dodawanie obiektówOdejmowanie obiektówŁączenie obiektówPorównywanie obiektów (<, >)Powtórka — działania na portfelu8Hermetyzacja
Konwencje nazewnictwaDomknięcia dla prywatnościDostęp za pomocą domknięćTabele tylko do odczytuLogika walidacjiPodsumowanie — bezpieczny sejf11Wzorce projektowe (podstawy)
Funkcje fabrykująceTabela SingletonWzorzec iteratoraObserwator (nasłuchujący)Powtórka — fabryka loggera3Stan i zachowanie obiektu
Zmienne instancjiMetody dostępoweMetody ustawiająceWłaściwości obliczaneFormatowanie ciągów znakówSprawdzanie równościPodsumowanie – ocena ucznia6Podstawy dziedziczenia
Konfiguracja dziedziczeniaDziedziczenie metodRozszerzanie konstruktoraDodawanie metod potomnychWspólne i unikalne elementyPowtórka — hierarchia kształtówPoćwicz samodzielnie: Kompilator Lua online