Zugriff über Closures
Teil des Abschnitts Objektorientierte Programmierung der Lua-Journey von Coddy — Lektion 45 von 70.
Private lokale Variablen sind nutzlos, wenn man niemals mit ihnen interagieren kann. Die Lösung besteht darin, Getter- und Setter-Methoden innerhalb des Konstruktors zu definieren — wo sie Zugriff auf den Scope des Closures haben.
Da diese Methoden innerhalb von :new() erstellt werden, können sie die lokalen Variablen „sehen“. Sie weisen sie direkt dem Objekt zu:
local Counter = {}
Counter.__index = Counter
function Counter:new()
local count = 0 -- Private Variable
local obj = {}
-- Methoden innerhalb des Konstruktors definieren
function obj:getCount()
return count
end
function obj:increment()
count = count + 1
end
setmetatable(obj, Counter)
return obj
endJetzt kann auf die private count Variable zugegriffen werden – aber nur über die von Ihnen 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!)Beachten Sie, dass :getCount() und :increment() direkt auf obj definiert sind, nicht in der Klassentabelle. Jede Instanz erhält ihre eigene Kopie dieser Funktionen, jede mit Zugriff auf ihr eigenes privates count. Dies ist der Kompromiss: Echte Privatsphäre kostet etwas mehr Speicher, da Methoden nicht über den Prototyp geteilt werden.
Aufgabe
EinfachLassen Sie uns eine Temperature-Klasse erstellen, die auf Closures basierende Privatsphäre nutzt, um einen Temperaturwert in Celsius zu speichern. Dabei werden Getter- und Setter-Methoden innerhalb des Konstruktors definiert, um einen kontrollierten Zugriff zu ermöglichen!
Sie werden Ihren Code auf zwei Dateien aufteilen:
Temperature.lua: Erstellen Sie eine Klasse, in der der Temperaturwert in einer lokalen Variable innerhalb des Konstruktors gespeichert wird – völlig verborgen vor externem Zugriff. Der Konstruktor:new(initialCelsius)sollte die Temperatur in einer lokalen Variable speichern und dann diese Methoden direkt auf der 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 unter Verwendung der Formel(celsius * 9/5) + 32zurück
main.lua: Binden Sie Ihr Temperature-Modul ein und lesen Sie zwei Werte von der Eingabe: eine Anfangstemperatur und eine neue Temperatur, die gesetzt werden soll. Erstellen Sie eine Temperature-Instanz mit dem Anfangswert, geben Sie die Celsius- und Fahrenheit-Werte aus, verwenden Sie dann den Setter, um die Temperatur zu ändern, und geben Sie beide Werte erneut aus.
Sie erhalten zwei Eingaben:
- Die Anfangstemperatur in Celsius (eine Zahl)
- Eine neue Temperatur, die gesetzt werden soll (eine Zahl)
Ihre Ausgabe sollte aus vier Zeilen bestehen, die die Temperaturwerte vor und nach der Änderung anzeigen:
Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}Wenn die Eingaben beispielsweise 0 und 100 sind, sollte die Ausgabe wie folgt aussehen:
Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212Denken Sie daran: Der Temperaturwert sollte in einer lokalen Variable innerhalb von :new() gespeichert werden, nicht auf self. Die Getter- und Setter-Methoden werden innerhalb des Konstruktors definiert, wo sie über eine Closure auf diese private Variable zugreifen können. Ein Versuch, direkt auf temp.celsius oder temp._celsius zuzugreifen, sollte nil zurückgeben!
Probier es selbst
-- Erfordere das Temperature-Modul
local Temperature = require('Temperature')
-- Eingabewerte lesen
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())
-- TODO: Erstelle eine Temperature-Instanz mit dem Initialwert
-- 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