Tabele tylko do odczytu
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 46 z 70.
Domknięcia zapewniają prawdziwą prywatność, ale wymagają definiowania metod wewnątrz konstruktora. Istnieje inne podejście do innego zastosowania: utworzenie obiektu tylko do odczytu po jego utworzeniu. Jest to przydatne, gdy chcesz, aby pola były widoczne, ale niezmienialne, na przykład współrzędne stałego punktu.
Metametoda __newindex przechwytuje próby przypisania nowych wartości do tabeli. Blokując wszystkie przypisania, możesz zamrozić obiekt:
local ImmutablePoint = {}
function ImmutablePoint.new(x, y)
local data = {x = x, y = y}
local proxy = {}
setmetatable(proxy, {
__index = data,
__newindex = function()
error("Cannot modify immutable object")
end
})
return proxy
endSztuczka polega na użyciu tabeli proxy. Rzeczywiste dane znajdują się w data, a użytkownik korzysta z pustej tabeli proxy.
Podczas odczytu __index pobiera dane z data. Podczas zapisu wywoływane jest zamiast tego __newindex, a my to blokujemy:
local p = ImmutablePoint.new(10, 20)
print(p.x) -- 10 (odczyt działa)
p.x = 50 -- Błąd: Nie można modyfikować niezmiennego obiektuTen wzorzec jest przydatny w przypadku obiektów konfiguracyjnych, stałych matematycznych lub dowolnych danych, które nie powinny się zmieniać po inicjalizacji. Obiekt pozostaje w pełni czytelny. Po prostu nie możesz go zmienić.
Wyzwanie
ŁatwyZbudujmy klasę ImmutableConfig, która tworzy obiekty konfiguracji tylko do odczytu! Po utworzeniu obiekty konfiguracji powinny pozwalać na odczytywanie ustawień, ale całkowicie blokować wszelkie próby ich modyfikacji.
Rozmieścisz swój kod w dwóch plikach:
ImmutableConfig.lua: Utwórz moduł, który tworzy zamrożone obiekty konfiguracji. Funkcja.new(appName, version, maxUsers)powinna przechowywać wewnętrznie te trzy wartości, a następnie zwracać tabelę proxy, która umożliwia odczyt wszystkich pól, ale uniemożliwia jakiekolwiek modyfikacje. Gdy ktoś spróbuje zmienić wartość, powinien zostać wyświetlony komunikatError: Config is read-only, zamiast wystąpić rzeczywisty błąd.main.lua: Ożyw swój ImmutableConfig! Wczytaj trzy wartości wejściowe konfiguracji, utwórz obiekt konfiguracji, a następnie pokaż, że działa poprawnie, wykonując następujące czynności:- Wyświetl wszystkie trzy pierwotne wartości
- Spróbuj zmodyfikować pole
maxUsers(co powinno wywołać komunikat o błędzie) - Ponownie wyświetl
maxUsers, aby udowodnić, że wartość nie została faktycznie zmieniona
Otrzymasz trzy wartości wejściowe:
- Nazwa aplikacji (ciąg znaków)
- Wersja (ciąg znaków)
- Maksymalna liczba użytkowników (liczba)
Wynik powinien pokazywać wartości konfiguracji, błąd występujący przy próbie modyfikacji oraz potwierdzenie, że wartość pozostała niezmieniona:
App: {appName}
Version: {version}
Max Users: {maxUsers}
Error: Config is read-only
Max Users: {maxUsers}Na przykład, jeśli wartości wejściowe to MyApp, 2.0 i 100, wynik powinien wyglądać następująco:
App: MyApp
Version: 2.0
Max Users: 100
Error: Config is read-only
Max Users: 100Pamiętaj: wzorzec proxy wykorzystuje pustą tabelę, z którą użytkownik wchodzi w interakcję, podczas gdy właściwe dane znajdują się w osobnej tabeli wewnętrznej. Metametoda __index pobiera dane z tabeli danych, a __newindex przechwytuje (i blokuje) każdą próbę zapisu!
Spróbuj swoich sił
-- Zaimportuj moduł ImmutableConfig
local ImmutableConfig = require('ImmutableConfig')
-- Wczytaj dane wejściowe
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())
-- TODO: Utwórz obiekt konfiguracyjny za pomocą ImmutableConfig.new()
-- TODO: Wyświetl wszystkie trzy pierwotne wartości w formacie:
-- Aplikacja: {appName}
-- Wersja: {version}
-- Maksymalna liczba użytkowników: {maxUsers}
-- TODO: Spróbuj zmodyfikować pole maxUsers (powinno to wywołać komunikat o błędzie)
-- TODO: Wyświetl ponownie maxUsers, aby potwierdzić, że jego wartość się nie zmieniła
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