Lua: 面向对象编程详解之类、继承、封装与多态实现

Lua 面向对象编程概述

1 ) 基础概念

  • 对象:用表(table)表示,包含属性(数据)和方法(函数)

  • 类:通过元表(metatable)模拟类的行为,实现方法共享

  • 继承:利用元表的 index 元方法实现属性和方法的继承链

  • 封装:通过闭包或局部变量实现数据隐藏(非强制)

  • 多态:动态函数调用,同一方法在不同对象中表现不同行为

    面向对象特性 Lua 实现方式 关键机制
    封装 使用 table 存储属性和方法,通过函数控制访问 闭包、局部变量、getter/setter
    继承 通过元表的 index 元方法实现方法和属性的继承 metatable、index
    多态 通过动态的函数调用实现多态行为 函数重写、动态绑定

2 ) 实现机制

  • 元表(Metatable):核心机制,控制表的查找、操作行为
  • index 元方法:实现继承和方法共享的关键
  • newindex 元方法:控制新增属性的赋值逻辑

3 ) 高级特性

  • 操作符重载(如 add、call)
  • 多重继承与 Mixin 模式
  • 私有性模拟(闭包 + 局部表)

核心实现细节与代码示例

1 ) 类与对象创建

lua 复制代码
-- 定义基类
Person = { name = "Unnamed" }
 
function Person:new(name)
    local obj = {}
    setmetatable(obj, self)          -- 绑定元表 
    self.index = self              -- 设置 index 指向自身 
    obj.name = name or self.name
    return obj
end
 
function Person:speak()
    print("I am " .. self.name)
end
--  创建对象 
local p = Person:new("Alice")
p:speak()  -- 输出: I am Alice

关键点:

  • new 方法创建新表并关联元表
  • index 确保对象可访问类的方法

2 ) 单继承实现

lua 复制代码
--- 子类 Student 继承 Person 
Student = Person:new()  -- 继承基类方法 
 
function Student:new(name, grade)
    local obj = Person:new(name)      -- 调用父类构造函数 
    setmetatable(obj, self)           -- 绑定子类元表
    self.index = self          
    obj.grade = grade or "Unknown"
    return obj 
end 
 
function Student:study()
    print(self.name .. " is studying in grade " .. self.grade)
end

--- 使用子类对象
local s = Student:new("Bob", 10)
s:speak()   -- 继承自 Person → "I am Bob"
s:study()   -- 子类方法 → "Bob is studying in grade 10"

关键点:

  • 子类通过 父类:new() 初始化父类属性
  • 子类元表覆盖父类,实现方法扩展

3 )封装与私有性模拟

lua 复制代码
function createAccount(balance)
    local privateData = { balance = balance }  -- 私有数据
 
    local obj = {}
    obj.deposit = function(amount)
        privateData.balance = privateData.balance + amount
    end 
    obj.getBalance = function()
        return privateData.balance 
    end
    return obj
end
 
local acc = createAccount(100)
acc.deposit(50)
print(acc.getBalance())  -- 输出: 150 
--- 无法直接访问 privateData.balance 

再来看一个封装例子

lua 复制代码
local function createPerson(name, age)
    local privateData = { name = name, age = age } -- 私有数据
    
    local obj = {}
    ---- 公共方法
    function obj.getName()
        return privateData.name
    end
    
    function obj.getAge()
        return privateData.age 
    end
    
    function obj.setAge(newAge)
        if newAge > 0 then
            privateData.age = newAge
        end
    end
    
    return obj
end 

local person = createPerson("Alice", 30)
print(person.getName()) -- 输出: Alice
print(person.getAge())  -- 输出: 30
person.setAge(31)
print(person.getAge())  -- 输出: 31
-- print(privateData.name) -- 错误!无法直接访问 privateData

关键点:

  • 闭包 + 局部变量隐藏数据,外部仅通过公开方法访问

4 ) 继承(Inheritance)

允许一个类(子类)继承另一个类(父类)的属性和方法

实现方式:通过元表和元方法来模拟

一个子类可以定义其自己的元表,该元表将父类对象作为其元方法的查找表

使用 setmetatable 和 index 来实现继承

示例代码(继承):

lua 复制代码
--- 父类
Animal = {}
function Animal:new(name)
    local obj = { name = name }
    setmetatable(obj, self)
    self.index = self 
    return obj 
end 

function Animal:speak()
    print(self.name .. " makes a sound.")
end

--- 子类
Dog = {}
setmetatable(Dog, {index = Animal}) -- Dog 继承 Animal 

function Dog:new(name, breed)
    local obj = Animal.new(self, name) -- 调用父类构造函数
    obj.breed = breed 
    setmetatable(obj, self)
    self.index = self 
    return obj 
end

function Dog:speak() -- 重写父类方法
    print(self.name .. " barks! Woof!")
end 

local myDog = Dog:new("Buddy", "Golden Retriever")
myDog:speak() -- 输出: Buddy barks! Woof!
print(myDog.name) -- 输出: Buddy (从父类继承)
print(myDog.breed) -- 输出: Golden Retriever (子类特有)

5 ) 多态(Polymorphism)

允许不同类的对象对同一消息做出响应的能力

实现方式:当一个函数或方法被调用时,它接收的对象类型可以是任何类的实例,这为多态提供了基础

通过函数的灵活性和方法重写来实现

示例代码(多态):

lua 复制代码
--- 假设已定义了 Animal, Dog, Cat 类(Cat 类类似 Dog)
--- Cat 类可能有 speak() 方法输出 "meows"

local animals = {myDog, myCat} -- 假设 myCat 也已创建 

for _, animal in ipairs(animals) do 
    animal:speak() -- 同一个方法调用,根据实例类型产生不同行为
end 
--- 输出:
--- Buddy barks! Woof!
--- Whiskers meows! (假设 myCat 名字是 Whiskers)

6 ) 多继承(Mixin 模式)

lua 复制代码
--- 定义多个基类 
Flyer = { canFly = true }
--- Swimmer = { canSwim = true }
--- 多重继承函数 
function multiInherit(...)
    local classes = { ... }
    local combined = {}
    for _, cls in ipairs(classes) do
        for k, v in pairs(cls) do 
            combined[k] = v
        end 
    end
    return combined
end
--- 创建多继承类 
Duck = multiInherit(Flyer, Swimmer)
Duck.quack = function() print("Quack!") end 
 
local duck = setmetatable({}, { index = Duck })
duck.quack()            -- Quack!
print(duck.canFly)      -- true 

关键点:

  • 合并多个基类的字段到新表
    需手动处理冲突方法

7 ) 操作符重载(元方法)

lua 复制代码
Vector = {}
function Vector:new(x, y)
    return setmetatable({ x = x, y = y }, self)
end 
Vector.add = function(a, b)
    return Vector:new(a.x + b.x, a.y + b.y)
end 
 
local v1 = Vector:new(1, 2)
local v2 = Vector:new(3, 4)
local v3 = v1 + v2  -- 调用 add
print(v3.x, v3.y)   -- 输出: 4, 6 

关键点:

  • 通过 add、sub 等元方法重载运算符

最佳实践与注意事项

1 ) 性能优化

  • 避免过度嵌套元表(影响查找效率),优先组合而非深继承链
  • 预缓存常用方法(如 local pairs = pairs)

2 ) 私有性限制:

  • Lua 无强制私有机制,依赖命名约定(如 _privateVar)或闭包

3 ) self 参数:

  • 用 obj:method() 语法(自动传递 self),代替 obj.method(obj)

4 ) 工厂模式:

统一入口创建对象,隐藏构造细节:

lua 复制代码
function CreateShape(type, ...)
    if type == "circle" then return Circle:new(...) end 
    if type == "rect" then return Rectangle:new(...) end
end 

完整代码库参考:云风 Lua OOP 实现,或 LuaRocks 模块 middleclass

补充说明

1 ) 冒号操作符 :

  • 在 Lua 中,obj:method(args) 等价于 obj.method(obj, args)
  • 冒号会自动将调用对象 (obj) 作为第一个参数(通常命名为 self)传递给方法。这使得方法内部可以访问对象自身的属性和方法

2 ) __index 元方法

  • 当访问一个表中不存在的键时,Lua 会查找该表的元表中的 __index 元方法。如果 __index 是一个表,Lua 会去该表中查找;
  • 如果 __index 是一个函数,则调用该函数。这正是实现继承查找链的关键机制
  • 构造函数:通常约定使用 new 作为构造函数名,用于创建类的新实例并初始化其属性

要点回顾

  • Lua 通过其核心数据结构 table 和元表机制,巧妙地模拟了面向对象编程的三大特性
  • 虽然语法上不如 Java、C++ 等原生 OOP 语言直观,但其灵活性和简洁性提供了强大的抽象能力
  • 掌握 tablemetatable__index 以及冒号调用语法是实现 Lua OOP 的关键
相关推荐
玖玥拾3 天前
Lua 基础语法(八) Unity Huatuo (HybridCLR)
开发语言·unity·游戏引擎·lua
x10n93 天前
Postman 汉化完整指南
测试工具·lua·postman
AI情绪识别开源4 天前
检信 Allemotion 认知功能障碍矫正软件体验评审意见报告
lua
玖玥拾5 天前
Lua 基础语法(六)xLua Lua 调用 C# 交互
开发语言·unity·c#·lua
玖玥拾6 天前
Lua 基础语法(五)Unity xLua基础配置与 C# 访问 Lua
开发语言·unity·c#·lua
玖玥拾6 天前
Lua 基础语法(二)
开发语言·unity·lua
玖玥拾7 天前
Lua 基础语法(三) 元表 metatable、元方法、模拟面向对象
开发语言·unity·lua
盟道科技8 天前
Redis+Lua 实现滑动窗口限流:从固定窗口踩坑到生产可用的完整方案
redis·junit·lua
Rain的Java大神之路11 天前
高并发下的热点账户余额扣减:Redis+Lua脚本实现无锁记账
java·spring boot·redis·后端·spring cloud·缓存·lua
qq_3227627512 天前
一个接口从能用到稳定,中间差的到底是什么
服务器·开发语言·lua·接口·fastapi·请求