Wzorzec iteratora
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 64 z 70.
Gdy masz kolekcję elementów przechowywaną w obiekcie, często chcesz przejść przez nią w pętli. Ogólna pętla for w Lua świetnie współpracuje z niestandardowymi iteratorami, a tę funkcjonalność możesz wbudować bezpośrednio w swoje klasy.
Wzorzec Iterator pozwala obiektowi kontrolować sposób przechodzenia przez jego wewnętrzne dane. Jedno eleganckie podejście wykorzystuje metametodę __call, która sprawia, że obiekt można wywołać jak funkcję. Każde wywołanie zwraca kolejny element, aż nie będzie już żadnych.
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
Po zdefiniowaniu __call możesz iterować za pomocą pętli while lub przekazać obiekt bezpośrednio do ogólnej pętli for:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag do
print(item)
end
Pętla wielokrotnie wywołuje bag(). Gdy __call zwraca nil (nie ma już więcej elementów), pętla się zatrzymuje. Ten wzorzec umieszcza logikę iteracji wewnątrz samego obiektu, dając Ci pełną kontrolę nad tym, jak i w jakiej kolejności uzyskuje się dostęp do elementów.
Wyzwanie
ŁatwyZbudujmy klasę Playlist, po której można iterować za pomocą ogólnej pętli for w Lua! Zaimplementujesz wzorzec Iteratora przy użyciu metametody __call, dzięki czemu będzie można przechodzić przez playlistę utwór po utworze.
Podzielisz swój kod na dwa pliki:
Playlist.lua: Utwórz klasę Playlist, która przechowuje utwory. Twoja klasa potrzebuje konstruktora:new(), który inicjuje pustą listę utworów i ustawia indeks iteracji na 0. Dodaj metodę:addSong(title), aby dodawać utwory do playlisty. Co najważniejsze, zaimplementuj metametodę__call, tak aby za każdym razem, gdy playlista zostanie "called", zwracała następny utwór z listy (lubnil, gdy nie ma już kolejnych 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ętlifor, aby przejść przez playlistę i wypisać tytuł każdego utworu w osobnym wierszu.
Magia wzorca Iteratora polega na tym, że obiekt Playlist staje się wywoływalny. Gdy użyjesz go w pętli for, Lua będzie wywoływać go wielokrotnie, aż zwróci nil, przekazując Ci kolejno każdy utwór.
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 danymi wejściowymi są Bohemian Rhapsody, Stairway to Heaven i Hotel California, wynikiem powinno być:
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaJeśli danymi wejściowymi są Yesterday, Imagine i Let It Be, wynikiem powinno być:
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, aby przejść przez playlistę
-- i wypisz każdy tytuł piosenki w osobnym wierszu
-- Wskazówka: for song in playlist 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