Menu
CoddyTech

Mixiny a dziedziczenie

Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 53 z 70.

Poznałeś dwa sposoby współdzielenia zachowania: dziedziczenie tworzy relację „jest czymś” za pośrednictwem łańcucha prototypów, a domieszki kopiują funkcje bezpośrednio do klasy. Kiedy jednak warto zastosować każde z tych podejść?

Używaj dziedziczenia, gdy obiekty mają wspólną, fundamentalną tożsamość. Bird jest Animal. Ma sens, aby Bird dziedziczył podstawowe zachowania zwierzęcia, takie jak :eat() czy :sleep(). Ta relacja jest trwała i określa, czym obiekt jest w swojej istocie.

Używaj mixins, gdy chcesz dodać możliwość, która nie definiuje podstawowej tożsamości obiektu.

Nie wszystkie ptaki potrafią latać: pingwiny i strusie to ptaki, ale nie latają. Latanie to umiejętność, a nie cecha definiująca ptaka. Mixin Flyable pozwala dodać możliwość latania ptakom, które jej potrzebują, bez narzucania jej wszystkim.

Te dwa podejścia współdziałają. Tutaj zarówno Eagle, jak i Penguin dziedziczą po Bird, a tylko Eagle otrzymuje domieszkę:

-- Bird dziedziczy po Animal (relacja „jest”)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- Eagle i Penguin są ptakami
local Eagle = setmetatable({}, {__index = Bird})
Eagle.__index = Eagle
local Penguin = setmetatable({}, {__index = Bird})
Penguin.__index = Penguin

-- Flyable to zdolność (miksin)
local Flyable = {}
function Flyable:fly()
    print(self.name .. " soars through the sky!")
end

-- Zastosuj miksin tylko do ptaków, które latają
applyMixin(Eagle, Flyable)

Orzeł może wywołać :fly(). Pingwin nie może: fly nie występuje w Penguin, Bird ani Animal, więc penguin:fly() powoduje błąd. Zastosowanie miksy do Bird skopiowałoby natomiast fly do każdego ptaka, w tym pingwinów.

challenge icon

Wyzwanie

Łatwy

Zbudujmy mały ekosystem stworzeń, który pokaże, kiedy używać dziedziczenia, a kiedy domieszek! Utworzysz klasę bazową Animal, klasę Bird, która po niej dziedziczy, oraz domieszkę Swimmable, ponieważ chociaż wszystkie ptaki są zwierzętami, nie wszystkie potrafią pływać.

Rozmieścisz swój kod w czterech plikach:

  • Animal.lua: Utwórz bazową klasę Animal z konstruktorem :new(name), który zapisuje nazwę. Dodaj metodę :eat(), która wypisuje {name} is eating. Reprezentuje ona podstawową tożsamość wspólną dla wszystkich zwierząt.
  • Swimmable.lua: Utwórz domieszkę z metodą :swim(), która wypisuje {self.name} is swimming. Jest to zdolność, której nie mają wszystkie stworzenia, więc nie powinna być częścią łańcucha dziedziczenia.
  • Bird.lua: Utwórz klasę Bird, która dziedziczy po Animal. Konstruktor :new(name) powinien wywoływać konstruktor klasy nadrzędnej. Dodaj metodę :chirp(), która wypisuje {name} chirps!. To zachowanie charakterystyczne dla ptaków. Nie umieszczaj pływania w klasie Bird: nie każdy ptak potrafi pływać.
  • main.lua: Napisz tutaj funkcję pomocniczą applyMixin(target, mixin): kopiuje ona wszystkie funkcje z domieszki do obiektu docelowego. Odczytaj imię ptaka i informację, czy potrafi pływać (yes lub no). Utwórz obiekt Bird i, jeśli potrafi pływać, zastosuj domieszkę Swimmable tylko do tego ptaka. Następnie wywołaj :eat() (odziedziczoną po Animal) oraz :chirp() (własną metodę Bird), a :swim() wywołaj tylko wtedy, gdy ten ptak ją ma (if bird.swim then).

Otrzymasz dwa wejścia:

  1. Imię ptaka (ciąg znaków)
  2. Informacja, czy ptak potrafi pływać: yes lub no

Jeśli ptak potrafi pływać, wynik powinien być następujący:

{name} is eating
{name} chirps!
{name} is swimming

Jeśli ptak nie potrafi pływać, wynik powinien być następujący:

{name} is eating
{name} chirps!

Na przykład, jeśli wejściami są Duck i yes, wynikiem powinno być:

Duck is eating
Duck chirps!
Duck is swimming

Jeśli wejściami są Sparrow i no, wynikiem powinno być:

Sparrow is eating
Sparrow chirps!

To wyzwanie pokazuje kluczową różnicę: Bird jest Animal (dziedziczenie), ale pływanie to opcjonalna zdolność (domieszka). Ponieważ domieszka trafia tylko do ptaków, które potrafią pływać, ptak, który nie potrafi pływać, w ogóle nie ma metody swim.

Spróbuj swoich sił

-- main.lua: Punkt wejścia — utwórz ptaka i zademonstruj jego umiejętności

-- Funkcja pomocnicza do zastosowania mixina do klasy lub pojedynczego obiektu
local function applyMixin(target, mixin)
    -- TODO: Skopiuj każdą funkcję z mixin do target

end

local Bird = require('Bird')
local Swimmable = require('Swimmable')

-- Odczytaj dane wejściowe
local name = io.read()
local canSwimInput = io.read()

-- TODO: Utwórz instancję Bird o podanej nazwie

-- TODO: Jeśli wartością wejściową jest "yes", zastosuj mixin Swimmable tylko do tego ptaka

-- TODO: Wywołaj eat() — metodę odziedziczoną po Animal

-- TODO: Wywołaj chirp() — własną metodę Bird

-- TODO: Wywołaj swim() tylko wtedy, gdy ten ptak ma tę metodę
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Lua online