Zugriff über Closures
Teil des Abschnitts Objektorientierte Programmierung der Lua-Journey von Coddy. Lektion 45 von 70.
Private lokale Variablen sind nutzlos, wenn du niemals mit ihnen interagieren kannst. Die Lösung besteht darin, Getter- und Setter-Methoden innerhalb des Konstruktors zu definieren, wo sie Zugriff auf den Gültigkeitsbereich der Closure haben.
Da diese Methoden innerhalb von :new() erstellt werden, können sie die lokalen Variablen „sehen“. Du weist sie direkt dem Objekt zu:
local Counter = {}
Counter.__index = Counter
function Counter:new()
local count = 0 -- Private Variable
local obj = {}
-- Methoden im Konstruktor definieren
function obj:getCount()
return count
end
function obj:increment()
count = count + 1
end
setmetatable(obj, Counter)
return obj
endJetzt kann auf die private Variable count zugegriffen werden, aber nur über die von dir bereitgestellten Methoden:
local c = Counter:new()
print(c:getCount()) -- 0
c:increment()
c:increment()
print(c:getCount()) -- 2
print(c.count) -- nil (immer noch versteckt!)Beachte, dass :getCount() und :increment() direkt auf obj definiert sind, nicht auf der Klassentabelle. Jede Instanz erhält ihre eigene Kopie dieser Funktionen, die jeweils Zugriff auf ihr eigenes privates count haben. Das ist der Kompromiss: Echte Privatsphäre kostet etwas mehr Speicher, da Methoden nicht über den Prototyp gemeinsam genutzt werden.
Aufgabe
EinfachBauen wir eine Temperature-Klasse, die Privatsphäre auf Basis eines Closures verwendet, um einen Temperaturwert in Celsius zu speichern, wobei Getter- und Setter-Methoden innerhalb des Konstruktors definiert werden, um kontrollierten Zugriff zu ermöglichen!
Du wirst deinen Code auf zwei Dateien verteilen:
Temperature.lua: Erstelle eine Klasse, in der der Temperaturwert in einer lokalen Variablen innerhalb des Konstruktors gespeichert wird: vollständig vor Zugriff von außen verborgen. Der Konstruktor:new(initialCelsius)sollte die Temperatur in einer lokalen Variablen speichern und anschließend diese Methoden direkt für die Objektinstanz definieren::getCelsius(): gibt die aktuelle Temperatur in Celsius zurück:setCelsius(value): aktualisiert die Temperatur auf einen neuen Wert:getFahrenheit(): gibt die in Fahrenheit umgerechnete Temperatur mithilfe der Formel(celsius * 9/5) + 32zurück
main.lua: Fordere dein Temperature-Modul an und lies zwei Werte aus der Eingabe: eine Anfangstemperatur und eine neue zu setzende Temperatur. Erstelle eine Temperature-Instanz mit dem Anfangswert, gib die Celsius- und Fahrenheit-Werte aus, verwende dann den Setter, um die Temperatur zu ändern, und gib beide Werte erneut aus.
Du erhältst zwei Eingaben:
- Die Anfangstemperatur in Celsius (eine Zahl)
- Eine neue zu setzende Temperatur (eine Zahl)
Deine Ausgabe sollte vier Zeilen enthalten, die die Temperaturwerte vor und nach der Änderung anzeigen:
Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}Wenn die Eingaben beispielsweise 0 und 100 lauten, sollte die Ausgabe folgendermaßen aussehen:
Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212Denke daran: Der Temperaturwert sollte in einer lokalen Variablen innerhalb von :new() gespeichert werden, nicht in self. Die Getter- und Setter-Methoden werden innerhalb des Konstruktors definiert, wo sie über ein Closure auf diese private Variable zugreifen können. Der Versuch, direkt auf temp.celsius oder temp._celsius zuzugreifen, sollte nil zurückgeben!
Probier es selbst
-- Temperature-Modul laden
local Temperature = require('Temperature')
-- Eingabewerte lesen
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())
-- TODO: Erstelle eine Temperature-Instanz mit dem Anfangswert
-- TODO: Gib die anfänglichen Celsius- und Fahrenheit-Werte aus
-- TODO: Verwende den Setter, um die Temperatur auf newTemp zu ändern
-- TODO: Gib die aktualisierten Celsius- und Fahrenheit-Werte aus
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-Mathematik8Kapselung
NamenskonventionenClosures für private DatenZugriff über ClosuresSchreibgeschützte TabellenValidierungslogikZusammenfassung – Sicherer Tresor3Objektzustand 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