Menu
CoddyTech

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

Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy. Урок 51 из 70.

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

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

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

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] Player создан

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

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

challenge icon

Задание

Легко

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

Вы распределите код по трём файлам:

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

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

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

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

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

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

Title: Lua Basics
Tags: programming, tutorial

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

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

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

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

-- TODO: Применить mixin Taggable к Article с помощью applyMixin

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

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

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

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

-- TODO: Вывести все теги с помощью метода listTags
quiz iconПроверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Lua