简单混入
本课属于 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 已创建与继承不同,混入不会创建父子关系。你只是在将函数从一个表复制到另一个表。
这使混入非常适合在彼此毫无共同点的类之间共享实用功能,例如日志记录、序列化或描述方法。
挑战
简单让我们用混入来构建一个标签系统!你将创建一个 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,给它添加两个标签,输出标题并列出所有标签。
你将收到三个输入:
- 文章标题(一个字符串)
- 要添加的第一个标签(一个字符串)
- 要添加的第二个标签(一个字符串)
你的输出应显示文章标题和后面的标签:
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 方法列出所有标签
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Lua 在线编译器