Lua 中的类继承是如何工作的?

我一直在阅读 Lua 教程关于继承,但我还不太理解如何实现它。假如我有以下两个类:

Hero = {}

function Hero.new(n)
  local self = {name = n, health = 100}

  local dealDamage = function(self)
    return 10
  end

  local takeDamage = function(self, h)
    self.health = self.health - h
  end

  local getHealth = function(self, h)
    self.health = self.health + h
  end

  local getName = function(self)
    return self.name
  end

  local isDead = function(self)
    if self.health <= 0 then
      return true
    end
  return false
  end

   local __tostring = function(self)
    return "Hero[姓名: "..self.name..", 生命值: "..self.health.."]"
  end

  local mt = {
    __tostring = __tostring
  }
  return setmetatable({
    name = self.name,
    health = self.health,
    dealDamage = dealDamage,
    takeDamage = takeDamage,
    getHealth = getHealth,
    getName = getName,
    isDead = isDead
  }, mt)
end
return Hero

heroClass = require "hero"
Fighter = {}

function Fighter.new(hero)
  local self = {strength = 3}

  local beserk = function(health)
    damage = heath * 0.33
    health = health - (health * 0.25
    return damage
  end

  local __tostring = function(self)
    return "Fighter[姓名: "..name..", 生命值: "..health.."]"
  end

  local mt = {
    __tostring = __tostring
  }
  return setmetatable({
      strength = self.strength,
    }, mt)
end

return Fighter

我的问题在于类的结构和元表的使用。使用这个例子或一些其他的SO问题,我发现我们的类非常不同。

如何正确设置继承,使得 Fighter 类可以继承 Hero 类的函数和数据字段?

点赞
用户3574628
用户3574628

有很多不同的方法可以在Lua中定义类。与选择一些面向对象程序设计系统作为"正确"方法不同,让我们看看你现在有的,尝试定义你的系统应该如何工作。

你的Hero类定义了一个构造函数,返回一个对象,其中包含所有方法和实例变量。这个概念相当简单。唯一的主要变化是删除顶部的self变量,因为你实际上并没有使用它:

function Hero.new(name)
  local dealDamage = function(self)
    return 10
  end

  local takeDamage = function(self, h)
    self.health = self.health - h
  end

  local getHealth = function(self, h)
    self.health = self.health + h
  end

  local getName = function(self)
    return self.name
  end

  local isDead = function(self)
    return self.health <= 0
  end

  local __tostring = function(self)
    return "Hero[Name: "..self.name..", health: "..self.health.."]"
  end

  local mt = {
    __tostring = __tostring
  }
  return setmetatable({
    name = name,
    health = 100,
    dealDamage = dealDamage,
    takeDamage = takeDamage,
    getHealth = getHealth,
    getName = getName,
    isDead = isDead
  }, mt)
end

对于你的Fighter类,我们可以从Hero创建一个基础实例,并使用__index进行继承(我删除了berserk函数,因为它未被使用。可以随意将其改编为该代码):

-- 我们需要与Hero相同的参数。
function Fighter.new(name)
  --通过实例化Hero来创建一个基础对象。
  local hero = heroClass.new(name)

  local __tostring = function(self)
    return "Fighter[Name: "..self.name..", health: "..self.health.."]"
  end

  local mt = {
    __tostring = __tostring,
    --从基础对象中继承。
    __index = hero,
  }
  return setmetatable({
      strength = 3,
  }, mt)
end

这个系统的优点是:

  1. 比大多数系统的引用更少。您只需查看对象的方法,而不是查找类表。

  2. 继承很灵活。您可以通过修改构造函数来更改其工作方式。您可以复制方法而不是使用__index,或者您可以在构造函数中实现多重继承!

我把这个系统的缺点留给读者作为练习。

2019-07-29 21:19:39