Menu
CoddyTech

简单混入

本课属于 Coddy Lua 学习旅程的“面向对象编程”单元。第 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 表。应用 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 构造函数负责。混入只提供共享行为!

亲手试试

-- 标签系统的主文件
local Taggable = require('Taggable')
local Article = require('Article')

-- TODO:实现 applyMixin 函数
-- 这个函数应将 mixin 表中的所有方法复制到目标表
function applyMixin(target, mixin)
    -- TODO:遍历 mixin,将每个方法复制到 target
end

-- 读取输入
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()

-- TODO:用给定的标题创建一个 Article 对象

-- TODO:将两个标签都添加到文章中

-- TODO:按 Title: {title} 格式打印标题

-- TODO:使用 listTags 方法列出所有标签
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Lua 在线编译器