Menu
Coddy logo textTech

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” za pośrednictwem łańcucha prototypów, a domieszki kopiują funkcje bezpośrednio do klasy. Kiedy jednak należy stosować każde z tych podejść?

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

Używaj domieszek, 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 zdolność, a nie cecha definiująca ptaka. Mixin Flyable pozwala dodać możliwość latania ptakom, które jej potrzebują, bez narzucania jej wszystkim.

Dwa podejścia świetnie ze sobą współgrają:

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

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

-- Zastosuj mixin tylko do ptaków, które potrafią latać
applyMixin(Bird, Flyable)

Ten wzorzec daje ci to, co najlepsze z obu światów: przejrzystą hierarchię klas, która zapewnia wspólną tożsamość, oraz elastyczne możliwości, które można dodawać w razie potrzeby.

challenge icon

Wyzwanie

Łatwy

Stwórzmy mały ekosystem stworzeń, który pokaże, kiedy używać dziedziczenia, a kiedy miksinów! Utworzysz klasę bazową Animal, klasę Bird, która po niej dziedziczy, oraz miksin Swimmable, ponieważ wszystkie ptaki są zwierzętami, ale nie wszystkie ptaki 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 imię. Dodaj metodę :eat(), która wypisuje {name} is eating. Reprezentuje ona podstawową tożsamość wspólną dla wszystkich zwierząt.
  • Swimmable.lua: Utwórz miksin z metodą :swim(), która wypisuje {self.name} is swimming. To zdolność — nie wszystkie stworzenia potrafią pływać, więc nie powinna być częścią łańcucha dziedziczenia.
  • Bird.lua: Utwórz klasę Bird, która dziedziczy po Animal. Konstruktor :new(name, canSwim) powinien wywołać konstruktor klasy nadrzędnej i zapisać, czy ten ptak potrafi pływać. Zastosuj miksin Swimmable do klasy Bird. Dodaj metodę :chirp(), która wypisuje {name} chirps!. To zachowanie charakterystyczne dla ptaków.
  • main.lua: Zdefiniuj tutaj funkcję pomocniczą applyMixin. Odczytaj dane wejściowe: imię ptaka i informację, czy potrafi pływać (yes lub no). Utwórz instancję Bird, a następnie pokaż jej zdolności: wywołaj :eat() (odziedziczoną po Animal), wywołaj :chirp() (własną metodę Bird) i wywołaj :swim() tylko wtedy, gdy ptak potrafi pływać.

Otrzymasz dwa dane wejściowe:

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

Jeśli ptak potrafi pływać, wynik powinien wyglądać tak:

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

Jeśli ptak nie potrafi pływać, wynik powinien wyglądać tak:

{name} is eating
{name} chirps!

Na przykład, jeśli dane wejściowe to Duck i yes, wynik powinien wyglądać tak:

Duck is eating
Duck chirps!
Duck is swimming

Jeśli dane wejściowe to Sparrow i no, wynik powinien wyglądać tak:

Sparrow is eating
Sparrow chirps!

To wyzwanie pokazuje kluczową różnicę: Bird jest Animal (dziedziczenie), ale pływanie to opcjonalna zdolność (miksin). Miksin jest stosowany do klasy, ale logika w pliku main decyduje, czy go użyć, na podstawie zdolności danego ptaka!

Spróbuj swoich sił

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

-- Funkcja pomocnicza do zastosowania miksinu w klasie
local function applyMixin(class, mixin)
    -- TODO: Skopiuj wszystkie metody z miksinu do klasy
    
end

-- Zastosuj miksin Swimmable w klasie Bird przed załadowaniem modułu Bird
-- Uwaga: Może być konieczne zrobienie tego w Bird.lua lub tutaj

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

-- Zastosuj miksin w klasie Bird
applyMixin(Bird, Swimmable)

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

-- TODO: Ustal na podstawie danych wejściowych, czy ptak potrafi pływać ("yes" lub "no")

-- TODO: Utwórz instancję Bird z podanym imieniem i informacją o umiejętności pływania

-- TODO: Wywołaj eat() – metodę odziedziczoną z Animal

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

-- TODO: Wywołaj swim() tylko wtedy, gdy ptak potrafi pływać
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