Closures für private Daten
Teil des Abschnitts Objektorientierte Programmierung der Lua-Journey von Coddy. Lektion 44 von 70.
Namenskonventionen signalisieren die Absicht, verhindern den Zugriff jedoch nicht tatsächlich. Jeder kann weiterhin player._health = 999 schreiben, und es funktioniert. Für wahre Privatsphäre bietet Lua einen anderen Ansatz: Daten in lokalen Variablen innerhalb des Konstruktors zu speichern, statt in self.
Die zentrale Erkenntnis ist, dass lokale Variablen innerhalb einer Funktion nur innerhalb dieser Funktion und aller darin definierten Funktionen zugänglich sind. Dies wird als Closure bezeichnet:
local Counter = {}
Counter.__index = Counter
function Counter:new()
local count = 0 -- Wirklich privat! Nicht auf self.
local obj = {}
setmetatable(obj, Counter)
return obj
endIn diesem Beispiel existiert count nur innerhalb der Funktion :new(). Es wird nicht in obj gespeichert, daher gibt es keine Möglichkeit, von außerhalb darauf zuzugreifen: myCounter.count gibt nil zurück, und es gibt kein Feld mit vorangestelltem Unterstrich, das als Umgehung dienen könnte.
Die Variable count lebt im Gültigkeitsbereich der closure. Sie bleibt vor externem Code vollständig verborgen. (So wie es geschrieben ist, erfasst noch nichts count; in der nächsten Lektion wirst du innerhalb des Konstruktors Methoden hinzufügen, die count einschließen, sodass es so lange bestehen bleibt wie das Objekt.) Anders als self._count, das nur ein höflicher Vorschlag ist, macht dieser Ansatz die Daten tatsächlich unzugänglich.
Natürlich sind verborgene Daten nicht nützlich, wenn du nie mit ihnen interagieren kannst. In der nächsten Lektion lernst du, wie du Methoden innerhalb des Konstruktors definierst, die diese privaten Variablen lesen und ändern können. So erhältst du kontrollierten Zugriff und bewahrst gleichzeitig eine echte Kapselung.
Aufgabe
EinfachErstellen wir eine SecretKeeper-Klasse, die mithilfe von Closures echten Datenschutz demonstriert! Anders als bei der Unterstrich-Konvention aus der vorherigen Lektion macht dieser Ansatz die Daten von außerhalb des Objekts tatsächlich unzugänglich.
Du wirst deinen Code auf zwei Dateien aufteilen:
SecretKeeper.lua: Erstelle eine Klasse, in der das Geheimnis in einer lokalen Variable innerhalb des Konstruktors gespeichert wird, nicht aufself. Der Konstruktor:new(secretValue)sollte das Geheimnis in einer lokalen Variable speichern, die nur innerhalb der Closure existiert. Das Objekt wird vorerst keine Möglichkeit haben, auf dieses Geheimnis zuzugreifen (das kommt in der nächsten Lektion!), aber du solltest außerdem ein öffentlichesname-Feld mit dem Wert"Keeper"auf der Instanz speichern, damit wir überprüfen können, dass das Objekt funktioniert.main.lua: Binde dein SecretKeeper-Modul ein und lies einen Geheimniswert aus der Eingabe. Erstelle mit diesem Geheimnis eine SecretKeeper-Instanz. Zeige dann, dass das Geheimnis tatsächlich privat ist, indem du drei Dinge ausgibst:- Das
name-Feld des Keepers (sollteKeeperausgeben) - Was passiert, wenn du versuchst, auf
keeper.secretzuzugreifen (solltenilsein) - Was passiert, wenn du versuchst, auf
keeper._secretzuzugreifen (sollte ebenfallsnilsein)
- Das
Du erhältst eine Eingabe:
- Der zu speichernde Geheimniswert (z. B.
TopSecret123)
Deine Ausgabe sollte aus drei Zeilen bestehen, die zeigen, dass das öffentliche Feld funktioniert, während das Geheimnis vollständig verborgen ist:
Name: Keeper
secret: nil
_secret: nilDie Ausgabe ist unabhängig davon, welches Geheimnis du übergibst, immer gleich, weil es keine Möglichkeit gibt, darauf zuzugreifen! Die lokale Variable innerhalb des Konstruktors ist für die Außenwelt unsichtbar. Dies beweist, dass der auf Closures basierende Datenschutz sich grundlegend von der Konvention zur Benennung mit Unterstrich unterscheidet.
Wenn die Eingabe beispielsweise MyPassword lautet, sollte die Ausgabe weiterhin so aussehen:
Name: Keeper
secret: nil
_secret: nilProbier es selbst
-- Lade das SecretKeeper-Modul
local SecretKeeper = require('SecretKeeper')
-- Lies den geheimen Wert von der Eingabe
local secretValue = io.read()
-- TODO: Erstelle eine SecretKeeper-Instanz mit dem geheimen Wert
-- TODO: Gib das name-Feld des keepers aus (Format: "Name: <name>")
-- TODO: Gib aus, was passiert, wenn auf keeper.secret zugegriffen wird (Format: "secret: <value>")
-- TODO: Gib aus, was passiert, wenn auf keeper._secret zugegriffen wird (Format: "_secret: <value>")
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