首页 > 解决方案 > 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[Name: "..self.name..", health: "..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: "..name..", health: "..health.."]" 
  end

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

return Fighter

我认为我做错的是如何使用元表构建类。使用这样的示例其他几个SO问题,我可以看到我们的课程非常不同。

如何正确设置 Fighter 类继承 Hero 类的函数和数据字段的继承?

标签: inheritancelua

解决方案


在 Lua 中有许多不同的定义类的方法。与其选择一些 OOP 系统作为“正确”的方式,不如让我们看看您拥有什么并尝试定义您的系统应该如何工作。

您的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功能,因为它没有被使用。请随意调整它以适应此代码。):

-- We need the same parameter as Hero.
function Fighter.new(name)
  -- Create a base object by instantiating Hero.
  local hero = heroClass.new(name)

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

  local mt = {
    __tostring = __tostring,
    -- Inherit from the base object.
    __index = hero,
  }
  return setmetatable({
      strength = 3,
  }, mt)
end

该系统的优点是:

  1. 与大多数系统相比,间接性更少。您可以只查看对象的方法,而不是查找类表。

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

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


推荐阅读