Proste mixiny
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 51 z 70.
Kompozycja pozwala umieszczać obiekty wewnątrz innych obiektów. A co, jeśli chcesz współdzielić zachowanie między niepowiązanymi klasami?
Zarówno Player, jak i MenuItem mogą potrzebować metody :describe(), ale nie mają wspólnej klasy nadrzędnej. Właśnie wtedy przydają się miksy.
Mixin to po prostu tabela zawierająca funkcje. „Mieszasz” te funkcje z klasą, kopiując je do niej:
local Printable = {}
function Printable:describe()
print("Object: " .. tostring(self))
end
function Printable:log(message)
print("[LOG] " .. message)
endAby zastosować tę domieszkę do klasy, kopiujesz każdą funkcję z tabeli domieszki do tabeli klasy:
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local Player = {}
Player.__index = Player
applyMixin(Player, Printable) -- Teraz Player ma :describe() i :log()Po zastosowaniu domieszki każda instancja Player może wywoływać te metody tak, jakby były zdefiniowane bezpośrednio w klasie:
local p = setmetatable({}, Player)
p:log("Player created") -- [LOG] Utworzono graczaW przeciwieństwie do dziedziczenia miksy nie tworzą relacji rodzic–dziecko. Po prostu kopiujesz funkcje z jednej tabeli do drugiej.
To sprawia, że miksy idealnie nadają się do współdzielenia użytecznych zachowań, takich jak logowanie, serializacja czy metody opisu, między klasami, które poza tym nie mają ze sobą nic wspólnego.
Wyzwanie
ŁatwyZbudujmy system tagowania z użyciem mixinów! Utworzysz mixin Taggable, który można zastosować do dowolnej klasy, dzięki czemu obiekty będą mogły zarządzać kolekcją tagów przydatnych do kategoryzowania elementów, postów lub dowolnych obiektów wymagających etykiet.
Rozmieścisz kod w trzech plikach:
Taggable.lua: Utwórz tabelę mixinu zawierającą dwie metody::addTag(tag): dodaje tag doself.tags(zakłada, że tabela istnieje):listTags(): wyświetla wszystkie tagi w formacieTags: tag1, tag2, tag3(lubTags: none, jeśli tabela jest pusta)
Article.lua: Utwórz klasę Article z konstruktorem:new(title), który zapisuje tytuł i inicjuje pustą tabelętags. Zastosuj mixin Taggable, aby instancje Article mogły obsługiwać tagi. Dodaj metodę:getTitle(), która zwraca tytuł artykułu.main.lua: Napisz tutaj funkcję pomocnicząapplyMixin(użyjesz jej w Article.lua za pomocą require). Następnie wczytaj tytuł artykułu i dwa tagi. Utwórz obiekt Article, dodaj do niego oba tagi, wyświetl tytuł i wypisz wszystkie tagi.
Otrzymasz trzy dane wejściowe:
- Tytuł artykułu (ciąg znaków)
- Pierwszy tag do dodania (ciąg znaków)
- Drugi tag do dodania (ciąg znaków)
Wynik powinien zawierać tytuł artykułu, a następnie jego tagi:
Title: {title}
Tags: {tag1}, {tag2}Na przykład, jeśli dane wejściowe to Lua Basics, programming i tutorial, wynik powinien wyglądać tak:
Title: Lua Basics
Tags: programming, tutorialPamiętaj: metody mixinu działają, ponieważ instancje Article mają tabelę tags, na której mogą operować metody mixinu. Mixin nie tworzy tej tabeli. Robi to konstruktor Article. Mixin zapewnia jedynie wspólne zachowanie!
Spróbuj swoich sił
-- Główny plik systemu tagowania
local Taggable = require('Taggable')
local Article = require('Article')
-- TODO: Zaimplementuj funkcję applyMixin
-- Ta funkcja powinna skopiować wszystkie metody z tabeli mixin do tabeli target
function applyMixin(target, mixin)
-- TODO: Przejdź przez tabelę mixin i skopiuj każdą metodę do target
end
-- Odczytaj dane wejściowe
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()
-- TODO: Utwórz Article z podanym tytułem
-- TODO: Dodaj oba tagi do artykułu
-- TODO: Wyświetl tytuł w formacie: Title: {title}
-- TODO: Wyświetl wszystkie tagi za pomocą metody listTags
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ów9Kompozycja i mixiny
Relacja Has-ADelegowanieProste mixinyStosowanie wielu mixinówMixiny a dziedziczeniePodsumowanie — składanie robotaPoćwicz samodzielnie: Kompilator Lua online