Menu
Coddy logo textTech

Простые примеси

Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 51 из 70.

Композиция позволяет помещать объекты внутрь других объектов. Но что, если вы хотите разделить поведение между несвязанными классами?

Объектам Player и MenuItem может потребоваться метод :describe(), но у них нет общего родительского класса. Именно здесь на помощь приходят примеси (mixins).

Миксин — это просто таблица, содержащая функции. Вы «подмешиваете» эти функции в класс, копируя их:

local Printable = {}

function Printable:describe()
    print("Object: " .. tostring(self))
end

function Printable:log(message)
    print("[LOG] " .. message)
end

Чтобы применить этот миксин к классу, вы копируете каждую функцию из таблицы миксина в таблицу класса:

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)  -- Теперь у Player есть :describe() и :log()

После применения миксина любой экземпляр Player может вызывать эти методы так, как если бы они были определены непосредственно в классе:

local p = setmetatable({}, Player)
p:log("Player created")  -- [LOG] Игрок создан

В отличие от наследования, примеси (mixins) не создают отношений «родитель-потомок». Вы просто копируете функции из одной таблицы в другую.

Это делает миксины идеальным решением для совместного использования вспомогательного поведения — такого как логирование, сериализация или методы описания — между классами, которые в остальном не имеют ничего общего.

challenge icon

Задание

Легко

Давайте создадим систему тегов, используя примеси (mixins)! Вы создадите примесь Taggable, которую можно применить к любому классу, наделяя объекты способностью управлять коллекцией тегов — это полезно для категоризации элементов, постов или любой сущности, которой нужны метки.

Вы организуете свой код в трех файлах:

  • Taggable.lua: Создайте таблицу примеси, содержащую два метода:
    • :addTag(tag) — добавляет тег в self.tags (предполагается, что таблица существует)
    • :listTags() — выводит все теги в формате Tags: tag1, tag2, tag3 (или Tags: none, если список пуст)
  • Article.lua: Создайте класс Article с конструктором :new(title), который сохраняет заголовок и инициализирует пустую таблицу tags. Примените примесь Taggable, чтобы наделить экземпляры Article возможностями тегирования. Включите метод :getTitle(), который возвращает заголовок статьи.
  • main.lua: Напишите здесь вспомогательную функцию applyMixin (вы будете использовать ее в Article.lua через require). Затем считайте входные данные для заголовка статьи и двух тегов. Создайте Article, добавьте в него оба тега, выведите заголовок и список всех тегов.

Вы получите три входных значения:

  1. Заголовок статьи (строка)
  2. Первый тег для добавления (строка)
  3. Второй тег для добавления (строка)

Ваш вывод должен отображать заголовок статьи, а затем ее теги:

Title: {title}
Tags: {tag1}, {tag2}

Например, если входные данные — Lua Basics, programming и tutorial, вывод должен быть следующим:

Title: Lua Basics
Tags: programming, tutorial

Помните: методы примеси работают потому, что у экземпляров Article есть таблица tags, с которой могут работать методы примеси. Примесь не создает эту таблицу — это делает ваш конструктор Article. Примесь просто предоставляет общее поведение!

Шпаргалка

Примесь (mixin) — это таблица, содержащая функции, которые могут использоваться в несвязанных классах без создания отношений родитель-потомок.

Чтобы создать примесь, определите таблицу с методами:

local Printable = {}

function Printable:describe()
    print("Object: " .. tostring(self))
end

function Printable:log(message)
    print("[LOG] " .. message)
end

Чтобы применить примесь к классу, скопируйте её функции в таблицу класса:

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)

После применения примеси экземпляры могут вызывать её методы:

local p = setmetatable({}, Player)
p:log("Player created")  -- [LOG] Player created

Примеси идеально подходят для совместного использования вспомогательного поведения, такого как логирование, сериализация или тегирование, в классах, не связанных наследованием.

Попробуйте сами

-- Основной файл для системы тегов
local Taggable = require('Taggable')
local Article = require('Article')

-- TODO: Реализовать функцию applyMixin
-- Эта функция должна копировать все методы из таблицы примеси (mixin) в целевую таблицу
function applyMixin(target, mixin)
    -- TODO: Пройтись циклом по примеси и скопировать каждый метод в целевую таблицу
end

-- Чтение входных данных
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()

-- TODO: Создать Article с заданным заголовком

-- TODO: Добавить оба тега к статье

-- TODO: Вывести заголовок в формате: Title: {title}

-- TODO: Вывести список всех тегов, используя метод listTags
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming