Iterator-Muster
Teil des Abschnitts Object Oriented Programming der Lua-Journey von Coddy — Lektion 64 von 70.
Wenn Sie eine Sammlung von Elementen haben, die in einem Objekt gespeichert sind, möchten Sie diese oft durchlaufen. Luas generische for-Schleife funktioniert hervorragend mit benutzerdefinierten Iteratoren, und Sie können diese Funktionalität direkt in Ihre Klassen einbauen.
Das Iterator-Muster ermöglicht es einem Objekt zu steuern, wie seine internen Daten durchlaufen werden. Ein eleganter Ansatz verwendet die __call-Metamethode, die ein Objekt wie eine Funktion aufrufbar macht. Jeder Aufruf gibt das nächste Element zurück, bis keine weiteren mehr vorhanden sind.
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
Mit __call definiert, können Sie mit einer while-Schleife iterieren oder das Objekt direkt an ein generisches for übergeben:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag do
print(item)
end
Die Schleife ruft bag() wiederholt auf. Wenn __call den Wert nil zurückgibt (keine weiteren Elemente), stoppt die Schleife. Dieses Muster kapselt die Iterationslogik innerhalb des Objekts selbst und gibt Ihnen die volle Kontrolle darüber, wie – und in welcher Reihenfolge – auf Elemente zugegriffen wird.
Aufgabe
EinfachLassen Sie uns eine Playlist-Klasse erstellen, die Sie mit Luas generischer for-Schleife durchlaufen können! Sie werden das Iterator-Muster unter Verwendung der __call-Metamethode implementieren, sodass Ihre Playlist Song für Song durchlaufen werden kann.
Sie werden Ihren Code auf zwei Dateien aufteilen:
Playlist.lua: Erstellen Sie eine Playlist-Klasse, die Songs intern speichert. Ihre Klasse benötigt einen:new()-Konstruktor, der eine leere Songliste initialisiert und den Iterationsindex auf 0 setzt. Fügen Sie eine:addSong(title)-Methode hinzu, um Songs zur Playlist hinzuzufügen. Am wichtigsten ist, dass Sie die__call-Metamethode implementieren, sodass jedes Mal, wenn die Playlist „aufgerufen“ wird, der nächste Song in der Liste zurückgegeben wird (odernil, wenn keine Songs mehr vorhanden sind).main.lua: Binden Sie Ihr Playlist-Modul ein und erstellen Sie eine neue Playlist. Fügen Sie Songs basierend auf den empfangenen Eingaben hinzu und verwenden Sie dann eine generischefor-Schleife, um die Playlist zu durchlaufen und jeden Songtitel in einer eigenen Zeile auszugeben.
Das Besondere am Iterator-Muster ist, dass Ihr Playlist-Objekt aufrufbar wird – wenn es in einer for-Schleife verwendet wird, ruft Lua es wiederholt auf, bis es nil zurückgibt, wodurch Sie jeden Song nacheinander erhalten.
Sie erhalten drei Eingaben, die jeweils einen Songtitel darstellen, der Ihrer Playlist (in der entsprechenden Reihenfolge) hinzugefügt werden soll.
Wenn die Eingaben beispielsweise Bohemian Rhapsody, Stairway to Heaven und Hotel California sind, sollte die Ausgabe wie folgt aussehen:
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaWenn die Eingaben Yesterday, Imagine und Let It Be sind, sollte die Ausgabe wie folgt aussehen:
Yesterday
Imagine
Let It BeSpickzettel
Das Iterator-Muster ermöglicht es einem Objekt zu steuern, wie seine internen Daten durchlaufen werden, indem eine benutzerdefinierte Iterationslogik implementiert wird.
Verwenden Sie die Metamethode __call, um ein Objekt wie eine Funktion aufrufbar zu machen. Jeder Aufruf gibt das nächste Element zurück, bis keine weiteren mehr vorhanden sind (gibt nil zurück):
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
Wenn __call definiert ist, können Sie das Objekt direkt in einer generischen for-Schleife verwenden:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag do
print(item)
end
Die Schleife ruft das Objekt wiederholt auf. Wenn __call den Wert nil zurückgibt, stoppt die Schleife automatisch.
Probier es selbst
-- Erfordert das Playlist-Modul
local Playlist = require('Playlist')
-- Drei Songtitel von der Eingabe lesen
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()
-- TODO: Erstelle eine neue Playlist mit Playlist:new()
-- TODO: Füge die drei Songs mit :addSong() zur Playlist hinzu
-- TODO: Verwende eine generische for-Schleife, um durch die Playlist zu iterieren
-- und gib jeden Songtitel in einer eigenen Zeile aus
-- Hinweis: for song in playlist do ... end
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Das 'self'-Konzept
Tabellen mit FunktionenExplizites 'self'Die Doppelpunkt-SyntaxPunkt vs. DoppelpunktZusammenfassung – Beweglicher Punkt4Projekt: Digitale Bank
Projekt-SetupEinzahlungsmethode7Polymorphie & Überschreiben
Methoden überschreibenElternmethoden aufrufenDuck TypingGemeinsames InterfaceTyp prüfenRückblick - Mitarbeiterrollen10Projekt: Formen-Manager
Projekt-SetupRechteck-Klasse2Klassen-Prototyp-Muster
Das Prototyp-KonzeptVerknüpfung mit __indexDer :new()-KonstruktorAttribute initialisierenUnabhängige InstanzenZusammenfassung – Autofabrik5Operatorüberladung in OOP
Objekte addierenObjekte subtrahierenObjekte verkettenObjekte vergleichen (<, >)Rückblick – Wallet-Mathematik8Kapselung
NamenskonventionenClosures für private DatenZugriff über ClosuresSchreibgeschützte TabellenValidierungslogikZusammenfassung – Sicherer Tresor11Entwurfsmuster (Lite)
Factory-FunktionenSingleton-TabelleIterator-MusterObserver (Listener)Wiederholung – Logger-Factory3Objektzustand und -verhalten
InstanzvariablenGetter-MethodenSetter-MethodenBerechnete EigenschaftenStrings formatierenGleichheitsprüfungenZusammenfassung – Studentennote6Grundlagen der Vererbung
Das Vererbungs-SetupMethoden vererbenDen Konstruktor erweiternChild-Methoden hinzufügenGemeinsam vs. EinzigartigZusammenfassung - Formen-Hierarchie9Komposition & Mixins
Has-A-BeziehungDelegationEinfache MixinsAnwendung mehrerer MixinsMixins vs. VererbungZusammenfassung – Roboter-Montage12Abschluss-Herausforderungen
Wiederholung - InventarsystemWiederholung - BenutzerverwaltungWiederholung - Score-TrackerFinaler OOP-Check