Menu
Coddy logo textTech

Zugriff über Closures

Teil des Abschnitts Object Oriented Programming 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
end

Jetzt 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.

challenge icon

Aufgabe

Einfach

Lassen 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) + 32 zurü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:

  1. Die Anfangstemperatur in Celsius (eine Zahl)
  2. 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: 212

Denken 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!

Spickzettel

Um wirklich private Variablen in Lua-Klassen zu erstellen, definieren Sie Getter- und Setter-Methoden innerhalb des Konstruktors, wo sie über Closures Zugriff auf lokale Variablen haben.

Methoden werden direkt der Objektinstanz zugewiesen (nicht der Klassentabelle), wodurch jede Instanz ihre eigene Kopie mit Zugriff auf ihre eigenen privaten Variablen erhält:

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
end

Verwendung:

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (immer noch verborgen!)

Kompromiss: Jede Instanz erhält ihre eigene Kopie der Methoden (nicht über den Prototyp geteilt), was mehr Speicher verbraucht, aber echte Privatsphäre bietet.

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
quiz iconTeste dich selbst

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