Menu
Coddy logo textTech

Typowanie kacze

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

Lua nie przejmuje się klasą obiektu. Liczy się tylko to, co obiekt potrafi zrobić. Ta koncepcja nazywa się typowaniem dynamicznym: „Jeśli chodzi jak kaczka i kwacze jak kaczka, to jest kaczką”. W terminologii programowania, jeśli obiekt ma metodę, którą wywołujesz, wszystko działa.

Oznacza to, że można używać razem zupełnie niezwiązanych ze sobą klas, o ile mają metodę o tej samej nazwie:

local Circle = {}
Circle.__index = Circle
function Circle:new() 
    local obj = {}
    setmetatable(obj, Circle)
    return obj
end
function Circle:draw()
    print("Drawing a circle")
end

local Square = {}
Square.__index = Square
function Square:new()
    local obj = {}
    setmetatable(obj, Square)
    return obj
end
function Square:draw()
    print("Drawing a square")
end

Te klasy nie są ze sobą powiązane dziedziczeniem: są całkowicie niezależne. Mimo to możemy traktować je identycznie:

local shapes = {Circle:new(), Square:new(), Circle:new()}

for _, shape in ipairs(shapes) do
    shape:draw()
end
-- Wynik:
-- Rysowanie koła
-- Rysowanie kwadratu
-- Rysowanie koła

Pętla nie sprawdza, jakiego typu jest każdy obiekt. Po prostu wywołuje :draw() i zakłada, że ta metoda istnieje. Ta elastyczność jest bardzo przydatna. Możesz dodawać nowe typy kształtów bez modyfikowania kodu pętli. Nowa klasa musi tylko implementować :draw(), a wszystko będzie działać.

challenge icon

Wyzwanie

Łatwy

Demonstrujmy moc duck typingu, tworząc system powiadomień z całkowicie niezależnych klas, które można przetwarzać w ten sam sposób!

Utworzysz trzy niezależne klasy powiadomień, z których żadna nie dziedziczy po pozostałych, ale wszystkie implementują metodę :send(). Oznacza to, że możesz iterować po mieszanej kolekcji i wywoływać :send() dla każdego elementu, nie przejmując się jego rzeczywistym typem.

Rozmieścisz swój kod w czterech plikach:

  • Email.lua: Klasa z konstruktorem :new(recipient), który przechowuje adresata wiadomości e-mail. Jej metoda :send() powinna wypisywać Emailing {recipient}.
  • SMS.lua: Całkowicie oddzielna klasa z konstruktorem :new(phoneNumber). Jej metoda :send() powinna wypisywać Texting {phoneNumber}.
  • PushNotification.lua: Kolejna niezależna klasa z konstruktorem :new(deviceId). Jej metoda :send() powinna wypisywać Pushing to {deviceId}.
  • main.lua: Połącz wszystko w całość! Odczytaj trzy dane wejściowe, utwórz jedną instancję każdego typu powiadomienia, umieść je wszystkie w jednej tabeli, a następnie iteruj po niej i wywołuj :send() dla każdego elementu.

Otrzymasz trzy dane wejściowe:

  1. Adresata wiadomości e-mail (np. alice@example.com)
  2. Numer telefonu (np. 555-1234)
  3. Identyfikator urządzenia (np. device_99)

W pliku głównym utwórz wszystkie trzy obiekty powiadomień, przechowaj je w tabeli i iteruj po niej, wywołując :send() dla każdego elementu. Kolejność powinna być następująca: najpierw Email, potem SMS, a na końcu PushNotification.

Na przykład jeśli danymi wejściowymi są bob@mail.com, 555-9876 i phone_42, wynikiem powinno być:

Emailing bob@mail.com
Texting 555-9876
Pushing to phone_42

Zauważ, że pętla nie musi sprawdzać, jakiego typu jest każdy obiekt. Po prostu zakłada, że każdy obiekt w kolekcji ma metodę :send(). Tak właśnie działa duck typing! Jeśli obiekt może wywołać :send(), jest powiadomieniem.

Spróbuj swoich sił

-- main.lua
-- Połącz wszystkie typy powiadomień i zademonstruj typowanie kacze

-- Zaimportuj klasy powiadomień
local Email = require('Email')
local SMS = require('SMS')
local PushNotification = require('PushNotification')

-- Odczytaj dane wejściowe
local recipient = io.read()
local phoneNumber = io.read()
local deviceId = io.read()

-- TODO: Utwórz po jednej instancji każdego typu powiadomienia

-- TODO: Umieść wszystkie powiadomienia w jednej tabeli (najpierw Email, potem SMS, a następnie PushNotification)

-- TODO: Przejdź przez tabelę i wywołaj :send() dla każdego powiadomienia
-- To demonstruje typowanie kacze — nie sprawdzamy typu, tylko wywołujemy :send()
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