应用多个混入
本课属于 Coddy Lua 学习旅程的“面向对象编程”单元。第 52 课,共 70 课。
单个混入会为类添加一组行为。但实际对象通常需要具备来自多个来源的能力。游戏对象可能既需要四处移动,又需要在屏幕上显示:这是两个不同的功能,不应该放在同一个混入中。
解决方法很简单:将多个混入应用到同一个类。每个混入都会提供自己的方法,最终这个类会拥有所有这些方法:
local Movable = {}
function Movable:move(dx, dy)
self.x = self.x + dx
self.y = self.y + dy
end
local Visible = {}
function Visible:show()
print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
print("Hidden")
end使用之前的同一个辅助函数,将两个混入都应用到你的类中:
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local GameObject = {}
GameObject.__index = GameObject
applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)现在,GameObject 实例既可以移动,也可以显示自己:
local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show() -- 显示在 5, 3 处注意:如果两个混入定义了同名方法,后应用的会覆盖先应用的。请让混入中的方法名称各不相同,以避免出现意外行为。
挑战
简单让我们用 mixin 为游戏创建一个具备多种能力的 Character 类吧!你的角色既能攻击敌人,也能治疗自己:这两种不同的行为分别来自独立的 mixin。
你会把代码分布在 4 个文件中:
Attacker.lua:创建一个 mixin,其中包含一个:attack(targetName)方法,用于打印{self.name} attacks {targetName} for {self.damage} damage!(假设对象具有name和damage字段)Healer.lua:创建一个 mixin,其中包含一个:heal(amount)方法,该方法会将 amount 加到self.health上,并打印{self.name} heals for {amount}. Health: {newHealth}Character.lua:创建一个 Character 类,其中包含构造函数:new(name, health, damage),用于存储这 3 个属性。应用 Attacker 和 Healer 两个 mixin,让每个角色都能攻击和治疗。添加一个:status()方法,用于打印{name} - Health: {health}, Damage: {damage}main.lua:在这里编写applyMixin辅助函数。读取角色的名称、生命值、伤害值、攻击目标和治疗量。创建一个 Character,显示其状态,让它攻击目标、治疗自己,然后再次显示其状态。
你会收到 5 个输入:
- 角色名称(字符串)
- 初始生命值(数字)
- 伤害值(数字)
- 攻击目标的名称(字符串)
- 治疗量(数字)
输出应显示角色使用了两个 mixin 的能力:
{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}例如,如果输入是 Warrior、100、25、Goblin 和 30,输出应为:
Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25每个 mixin 都会为 Character 类提供自己的方法。角色不会继承任何一个 mixin,而是通过 applyMixin 函数获得它们的能力。这就是组合多个 mixin 的优势!
亲手试试
-- 主文件
-- TODO: 编写 applyMixin 辅助函数
-- 这个函数应将 mixin 表中的所有方法复制到目标表中
local function applyMixin(target, mixin)
-- TODO: 实现 mixin 的应用
end
-- 让 applyMixin 在全局范围内可用,以便 Character.lua 使用
_G.applyMixin = applyMixin
local Character = require('Character')
-- 读取输入
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())
-- TODO: 用给定的 name、health 和 damage 创建一个 Character
-- TODO: 显示角色的状态
-- TODO: 让角色攻击目标
-- TODO: 让角色治疗自己
-- TODO: 再次显示角色的状态
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Lua 在线编译器