Wspólne i unikalne elementy
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 35 z 70.
Podczas pracy z dziedziczeniem ważne jest, aby rozumieć, gdzie znajduje się każdy element danych. Niektóre atrybuty są współdzielone: zdefiniowane w klasie nadrzędnej i dostępne dla wszystkich klas potomnych. Inne są unikalne: utworzone specjalnie w klasie potomnej lub instancji.
Rozważ tę hierarchię:
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- Wspólne: zdefiniowane w klasie
function Animal:new(name)
local obj = {name = name} -- Unikalne: przechowywane w każdej instancji
setmetatable(obj, Animal)
return obj
endlocal Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- Wspólne dla wszystkich obiektów Dog
function Dog:new(name, breed)
local obj = Animal.new(Animal, name)
obj.breed = breed -- Unikalne: każdy obiekt Dog ma własną rasę
setmetatable(obj, Dog)
return obj
endGdy tworzysz instancję Dog, niektóre wartości znajdują się bezpośrednio w obiekcie, a inne są wyszukiwane w łańcuchu wyszukiwania:
local rex = Dog:new("Rex", "German Shepherd")
-- Unikalne dla tej instancji (przechowywane w rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"-- Współdzielone (znalezione przez wyszukiwanie)
print(rex.sound) -- "bark" (z Dog)
print(rex.kingdom) -- "Animalia" (z Animal)Kluczowa różnica: pola przypisane do obj w konstruktorach są unikalne dla każdej instancji, natomiast pola zdefiniowane bezpośrednio w tabelach klas są współdzielone przez wszystkie instancje tej klasy i jej klas potomnych.
Wyzwanie
ŁatwyPrzyjrzyjmy się, jak dane przepływają przez hierarchię dziedziczenia, tworząc system klas Creature i Dragon. Zobaczysz na własne oczy, które atrybuty są współdzielone przez wszystkie instancje, a które są unikalne dla każdego obiektu.
Rozmieścisz swój kod w trzech plikach:
Creature.lua: Zdefiniuj klasę nadrzędną ze współdzielonym atrybutem na poziomie klasyworld = "Fantasy Realm", który jest wspólny dla wszystkich stworzeń. Dodaj konstruktor:new(name), który zapisuje imię stworzenia jako atrybut instancji.Dragon.lua: Zdefiniuj klasę podrzędną dziedziczącą po Creature. Dodaj współdzielony atrybut na poziomie klasyelement = "fire", który jest wspólny dla wszystkich smoków. Konstruktor:new(name, color)powinien wywołać konstruktor klasy nadrzędnej, przekazując imię, a następnie dodaćcolorjako unikalny atrybut instancji każdego smoka.main.lua: Utwórz dwa różne smoki i sprawdź ich atrybuty, aby pokazać różnicę między danymi współdzielonymi a unikalnymi.
Otrzymasz dwa wejścia:
- Imię i kolor pierwszego smoka, oddzielone przecinkiem (np.
Smaug,red) - Imię i kolor drugiego smoka, oddzielone przecinkiem (np.
Draco,gold)
W pliku głównym utwórz oba smoki, używając odpowiednich imion i kolorów. Następnie wypisz poniższe informacje dokładnie w tej kolejności:
namepierwszego smokacolorpierwszego smokanamedrugiego smokacolordrugiego smokaelementpierwszego smoka (współdzielony z klasy Dragon)elementdrugiego smoka (współdzielony z klasy Dragon)worldpierwszego smoka (współdzielony z klasy Creature)
Na przykład, jeśli wejściami są Smaug,red i Draco,gold, wynikiem powinno być:
Smaug
red
Draco
gold
fire
fire
Fantasy RealmZwróć uwagę, że name i color różnią się dla każdego smoka (unikalne atrybuty instancji), natomiast element i world są takie same dla obu (współdzielone atrybuty klasy odnajdywane w łańcuchu wyszukiwania).
Spróbuj swoich sił
-- main.lua: Utwórz smoki i pokaż atrybuty wspólne oraz unikalne
local Dragon = require('Dragon')
-- Odczytaj dane pierwszego smoka (imię, kolor)
local input1 = io.read()
-- Odczytaj dane drugiego smoka (imię, kolor)
local input2 = io.read()
-- TODO: Przeanalizuj pierwsze dane wejściowe, aby wyodrębnić imię i kolor
-- Wskazówka: Użyj string.match ze wzorcem "([^,]+),([^,]+)"
-- TODO: Przeanalizuj drugie dane wejściowe, aby wyodrębnić imię i kolor
-- TODO: Utwórz pierwszego smoka, podając jego imię i kolor
-- TODO: Utwórz drugiego smoka, podając jego imię i kolor
-- TODO: Wypisz kolejno:
-- 1. Imię pierwszego smoka
-- 2. Kolor pierwszego smoka
-- 3. Imię drugiego smoka
-- 4. Kolor drugiego smoka
-- 5. Żywioł pierwszego smoka (współdzielony przez klasę Dragon)
-- 6. Żywioł drugiego smoka (współdzielony przez klasę Dragon)
-- 7. Świat pierwszego smoka (współdzielony przez klasę Creature)
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