Menu
CoddyTech

Stosowanie wielu mixinów

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

Pojedynczy mixin dodaje do klasy jeden zestaw zachowań. Jednak rzeczywiste obiekty często potrzebują możliwości z wielu źródeł. Obiekt gry może potrzebować poruszać się i być widoczny na ekranie: to dwie odrębne kwestie, które nie powinny należeć do tego samego mixina.

Rozwiązanie jest proste: zastosuj wiele miksinów do tej samej klasy. Każdy miksin wnosi własne metody, a klasa ostatecznie ma je wszystkie:

local Movable = {}
function Movable:move(dx, dy)
    self.x = self.x + dx
    self.y = self.y + dy
end

local Visible = {}
function Visible:show()
    print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
    print("Hidden")
end

Zastosuj obie domieszki do swojej klasy, używając tej samej funkcji pomocniczej co wcześniej:

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local GameObject = {}
GameObject.__index = GameObject

applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)

Teraz instancje GameObject mogą się poruszać i wyświetlać:

local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show()  -- Wyświetlanie w położeniu 5, 3

Jedna uwaga: jeśli dwie domieszki definiują metodę o tej samej nazwie, druga zastosowana nadpisze pierwszą. Zadbaj o to, by metody w domieszkach miały różne nazwy, aby uniknąć nieoczekiwanego działania.

challenge icon

Wyzwanie

Łatwy

Zbudujmy klasę Character na potrzeby gry, która łączy wiele możliwości za pomocą mixinów! Twoja postać będzie mogła zarówno atakować wrogów, jak i się leczyć: będą to dwa odrębne zachowania pochodzące z osobnych mixinów.

Rozmieścisz kod w czterech plikach:

  • Attacker.lua: Utwórz mixin z metodą :attack(targetName), która wyświetla {self.name} attacks {targetName} for {self.damage} damage! (zakłada, że obiekt ma pola name i damage)
  • Healer.lua: Utwórz mixin z metodą :heal(amount), która dodaje tę wartość do self.health i wyświetla {self.name} heals for {amount}. Health: {newHealth}
  • Character.lua: Utwórz klasę Character z konstruktorem :new(name, health, damage), który zapisuje wszystkie trzy atrybuty. Zastosuj mixiny Attacker i Healer, aby każda postać mogła atakować i się leczyć. Dodaj metodę :status(), która wyświetla {name} - Health: {health}, Damage: {damage}
  • main.lua: Napisz tutaj funkcję pomocniczą applyMixin. Odczytaj dane wejściowe: imię postaci, zdrowie, obrażenia, cel ataku i ilość leczenia. Utwórz postać Character, wyświetl jej status, każ jej zaatakować cel, uleczyć się, a następnie ponownie wyświetl jej status.

Otrzymasz pięć danych wejściowych:

  1. Imię postaci (ciąg znaków)
  2. Początkowe zdrowie (liczba)
  3. Wartość obrażeń (liczba)
  4. Imię celu ataku (ciąg znaków)
  5. Ilość leczenia (liczba)

Wynik powinien pokazywać postać korzystającą z obu umiejętności mixinów:

{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}

Na przykład, jeśli danymi wejściowymi są Warrior, 100, 25, Goblin i 30, wynikiem powinno być:

Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25

Każdy mixin dodaje własną metodę do klasy Character. Postać nie dziedziczy po żadnym z mixinów. Po prostu zyskuje ich możliwości dzięki funkcji applyMixin. Na tym polega siła łączenia wielu mixinów!

Spróbuj swoich sił

-- Plik główny

-- TODO: Napisz funkcję pomocniczą applyMixin
-- Ta funkcja powinna skopiować wszystkie metody z tabeli mixin do tabeli docelowej
local function applyMixin(target, mixin)
    -- TODO: Zaimplementuj zastosowanie mixin
end

-- Udostępnij applyMixin globalnie, aby Character.lua mógł z niej korzystać
_G.applyMixin = applyMixin

local Character = require('Character')

-- Odczytaj dane wejściowe
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())

-- TODO: Utwórz obiekt Character o podanych nazwie, zdrowiu i obrażeniach

-- TODO: Wyświetl stan postaci

-- TODO: Niech postać zaatakuje cel

-- TODO: Niech postać się uleczy

-- TODO: Ponownie wyświetl stan postaci
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