Dostęp za pomocą domknięć
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 45 z 70.
Prywatne zmienne lokalne są bezużyteczne, jeśli nie możesz z nimi wchodzić w interakcję. Rozwiązaniem jest zdefiniowanie metod pobierających i ustawiających wewnątrz konstruktora, gdzie mają dostęp do zakresu domknięcia.
Ponieważ te metody są tworzone wewnątrz :new(), mogą „widzieć” zmienne lokalne. Przypisujesz je bezpośrednio do obiektu:
local Counter = {}
Counter.__index = Counter
function Counter:new()
local count = 0 -- Zmienna prywatna
local obj = {}
-- Zdefiniuj metody wewnątrz konstruktora
function obj:getCount()
return count
end
function obj:increment()
count = count + 1
end
setmetatable(obj, Counter)
return obj
endTeraz można uzyskać dostęp do prywatnej zmiennej count, ale tylko za pomocą udostępnionych przez ciebie metod:
local c = Counter:new()
print(c:getCount()) -- 0
c:increment()
c:increment()
print(c:getCount()) -- 2
print(c.count) -- nil (nadal ukryte!)Zwróć uwagę, że :getCount() i :increment() są zdefiniowane bezpośrednio w obj, a nie w tabeli klasy. Każda instancja otrzymuje własną kopię tych funkcji, z których każda ma dostęp do własnej prywatnej wartości count. To kompromis: prawdziwa prywatność wymaga nieco więcej pamięci, ponieważ metody nie są współdzielone za pośrednictwem prototypu.
Wyzwanie
ŁatwyStwórzmy klasę Temperature, która wykorzystuje prywatność opartą na domknięciu, aby przechowywać wartość temperatury w stopniach Celsjusza, z metodami pobierającą i ustawiającą zdefiniowanymi wewnątrz konstruktora, by zapewnić kontrolowany dostęp!
Podzielisz kod na dwa pliki:
Temperature.lua: Utwórz klasę, w której wartość temperatury jest przechowywana w zmiennej lokalnej wewnątrz konstruktora, całkowicie ukrytej przed dostępem z zewnątrz. Konstruktor:new(initialCelsius)powinien przechować temperaturę w zmiennej lokalnej, a następnie zdefiniować te metody bezpośrednio w instancji obiektu::getCelsius(): zwraca bieżącą temperaturę w stopniach Celsjusza:setCelsius(value): aktualizuje temperaturę, ustawiając nową wartość:getFahrenheit(): zwraca temperaturę przeliczoną na stopnie Fahrenheita za pomocą wzoru:(celsius * 9/5) + 32
main.lua: Załaduj moduł Temperature i odczytaj z wejścia dwie wartości: temperaturę początkową i nową temperaturę do ustawienia. Utwórz instancję Temperature z wartością początkową, wyświetl odczyty w stopniach Celsjusza i Fahrenheita, a następnie użyj metody ustawiającej, aby zmienić temperaturę i ponownie wyświetl oba odczyty.
Otrzymasz dwa wejścia:
- Początkową temperaturę w stopniach Celsjusza (liczbę)
- Nową temperaturę do ustawienia (liczbę)
Wynik powinien składać się z czterech wierszy pokazujących odczyty temperatury przed zmianą i po niej:
Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}Na przykład, jeśli dane wejściowe to 0 i 100, wynik powinien wyglądać tak:
Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212Pamiętaj: wartość temperatury powinna być przechowywana w zmiennej lokalnej wewnątrz :new(), a nie w self. Metody pobierająca i ustawiająca są definiowane wewnątrz konstruktora, gdzie mogą uzyskać dostęp do tej prywatnej zmiennej przez domknięcie. Próba bezpośredniego dostępu do temp.celsius lub temp._celsius powinna zwrócić nil!
Spróbuj swoich sił
-- Załaduj moduł Temperature za pomocą require
local Temperature = require('Temperature')
-- Odczytaj wartości wejściowe
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())
-- TODO: Utwórz instancję Temperature z wartością początkową
-- TODO: Wypisz początkowe odczyty w stopniach Celsjusza i Fahrenheita
-- TODO: Użyj settera, aby zmienić temperaturę na newTemp
-- TODO: Wypisz zaktualizowane odczyty w stopniach Celsjusza i Fahrenheita
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Koncepcja „self”
Tabele z funkcjamiJawne „self”Składnia z dwukropkiemKropka czy dwukropekPodsumowanie — poruszający się punkt4Projekt: Bank cyfrowy
Konfiguracja projektuMetoda wpłaty7Polimorfizm i nadpisywanie
Nadpisywanie metodWywoływanie metod klasy nadrzędnejTypowanie kaczeWspólny interfejsSprawdzanie typuPodsumowanie — role pracowników10Projekt: Menedżer kształtów
Konfiguracja projektuKlasa prostokątaKlasa kołaMetoda obwoduKolekcja kształtówPole całkowiteFiltrowanie kształtów2Wzorzec prototypu klasy
Koncepcja prototypuŁączenie za pomocą __indexKonstruktor :new()Inicjalizacja atrybutówNiezależne instancjePodsumowanie – fabryka samochodów5Przeciążanie operatorów w OOP
Dodawanie obiektówOdejmowanie obiektówŁączenie obiektówPorównywanie obiektów (<, >)Powtórka — działania na portfelu8Hermetyzacja
Konwencje nazewnictwaDomknięcia dla prywatnościDostęp za pomocą domknięćTabele tylko do odczytuLogika walidacjiPodsumowanie — bezpieczny sejf11Wzorce projektowe (podstawy)
Funkcje fabrykująceTabela SingletonWzorzec iteratoraObserwator (nasłuchujący)Powtórka — fabryka loggera3Stan i zachowanie obiektu
Zmienne instancjiMetody dostępoweMetody ustawiająceWłaściwości obliczaneFormatowanie ciągów znakówSprawdzanie równościPodsumowanie – ocena ucznia6Podstawy dziedziczenia
Konfiguracja dziedziczeniaDziedziczenie metodRozszerzanie konstruktoraDodawanie metod potomnychWspólne i unikalne elementyPowtórka — hierarchia kształtówPoćwicz samodzielnie: Kompilator Lua online