Den Konstruktor erweitern
Teil des Abschnitts Objektorientierte Programmierung der Lua-Journey von Coddy. Lektion 33 von 70.
Wenn eine untergeordnete Klasse von einer übergeordneten Klasse erbt, möchtest du häufig, dass der Konstruktor der untergeordneten Klasse alles initialisiert, was auch die übergeordnete Klasse initialisieren würde, sowie alle zusätzlichen Felder, die speziell für die untergeordnete Klasse gelten. Anstatt Code zu duplizieren, kannst du den Konstruktor der übergeordneten Klasse direkt aufrufen.
Die Technik besteht darin, den Namen der übergeordneten Klasse zu verwenden, um ihre :new()-Methode aufzurufen und dabei self als erstes Argument zu übergeben. Dadurch wird das Basisobjekt mit der gesamten Initialisierung der übergeordneten Klasse erstellt, das du anschließend für die untergeordnete Klasse anpasst.
local Vehicle = {}
Vehicle.__index = Vehicle
function Vehicle:new(speed)
local obj = {speed = speed}
setmetatable(obj, Vehicle)
return obj
end
-- Car erbt von Vehicle
local Car = {}
Car.__index = Car
setmetatable(Car, {__index = Vehicle})
function Car:new(speed, brand)
local obj = Vehicle.new(Vehicle, speed) -- Elternkonstruktor aufrufen
obj.brand = brand -- Kind-spezifisches Feld hinzufügen
setmetatable(obj, Car) -- Erneut mit Car verknüpfen
return obj
endBeachte die wichtigsten Schritte im Konstruktor der Kindklasse: Zuerst rufen wir Vehicle.new(Vehicle, speed) auf, um ein Objekt zu erhalten, bei dem das Feld speed bereits gesetzt ist. Dann fügen wir das kinderspezifische Feld brand hinzu. Schließlich ändern wir die Metatabelle von Vehicle zu Car, damit die Instanz zuerst in der Kindklasse nach Methoden sucht.
Du kannst beim Aufrufen des Konstruktors der übergeordneten Klasse auch die Doppelpunktsyntax verwenden: Vehicle:new(speed) ist gleichbedeutend mit Vehicle.new(Vehicle, speed), da beide Vehicle als erstes Argument übergeben. Beide Formen funktionieren hier korrekt. Verwende also einfach diejenige, die du lesbarer findest.
local myCar = Car:new(120, "Toyota")
print(myCar.speed) -- Ausgabe: 120
print(myCar.brand) -- Ausgabe: ToyotaDieses Muster hält deinen Code DRY: Die gemeinsame Initialisierungslogik befindet sich im übergeordneten Element, während jedes untergeordnete Element nur seine eindeutigen Attribute behandelt.
Aufgabe
EinfachErstellen wir eine Hierarchie von Lebewesen, in der eine Kindklasse den Konstruktor ihrer Elternklasse erweitert! Du erstellst eine Animal-Elternklasse und eine Bird-Kindklasse, deren Konstruktor den Konstruktor von Animal aufruft, um die gemeinsame Initialisierung zu übernehmen, bevor er ein eigenes, einzigartiges Attribut hinzufügt.
Du organisierst deinen Code auf drei Dateien verteilt:
Animal.lua: Definiere deine Elternklasse mit einem:new(name)-Konstruktor, der den Namen des Tiers speichert. Füge eine:describe()-Methode hinzu, die den Namen des Tiers ausgibt. Richte das standardmäßige Klassenmuster mit__indexein und gib die Klasse zurück.Bird.lua: Definiere deine Kindklasse, die von Animal erbt. Der:new(name, wingspan)-Konstruktor von Bird sollte den Konstruktor der Elternklasse mitAnimal.new(Animal, name)aufrufen, um den Namen zu initialisieren, anschließend das Feldwingspanzum Objekt hinzufügen und schließlich die Metatabelle wieder mit Bird verknüpfen. Füge eine:info()-Methode hinzu, die sowohl den Namen als auch die Flügelspannweite in einem bestimmten Format ausgibt.main.lua: Binde dein Bird-Modul ein, lies zwei Eingaben (Name und Flügelspannweite) ein, erstelle eine Bird-Instanz und rufe beide Methoden auf, um zu zeigen, dass geerbte und kinderspezifische Funktionen zusammenarbeiten.
Du erhältst zwei Eingaben:
- Der Name des Vogels
- Die Flügelspannweite des Vogels (eine Zahl)
Erstelle in deiner Hauptdatei einen Bird mit dem angegebenen Namen und der angegebenen Flügelspannweite. Rufe anschließend :describe() und danach :info() in separaten Zeilen auf.
Die Methode :describe() (von Animal geerbt) sollte Folgendes ausgeben:
Animal: {name}Die Methode :info() (in Bird definiert) sollte Folgendes ausgeben:
{name} has a wingspan of {wingspan}Wenn die Eingaben beispielsweise Eagle und 200 lauten, sollte die Ausgabe folgendermaßen aussehen:
Animal: Eagle
Eagle has a wingspan of 200Der entscheidende Punkt ist, dass dein Bird-Konstruktor die Initialisierung des Namens nicht dupliziert. Er überträgt diese Aufgabe an den Konstruktor von Animal und fügt anschließend nur das hinzu, was für Vögel einzigartig ist. So bleibt dein Code DRY und bildet gleichzeitig eine ordnungsgemäße Vererbungskette!
Probier es selbst
-- main.lua: Einstiegspunkt
local Bird = require('Bird')
-- Eingaben lesen
local name = io.read()
local wingspan = tonumber(io.read())
-- TODO: Erstelle eine Bird-Instanz mit dem gegebenen name und wingspan
-- TODO: Rufe :describe() auf dem bird auf (geerbt von Animal)
-- TODO: Rufe :info() auf dem bird auf (definiert in Bird)
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
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-KlasseKreis-KlasseUmfang-MethodeFormen-SammlungGesamtflächeFormen filtern2Klassen-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-Mathematik3Objektzustand 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Übe selbstständig: Online-Lua-Compiler