Lua没有类与对象的概念,但是可以用下面的方法来模拟出面向对象的效果来实现封装、继承、多态的面向对象特点
模拟类和对象,构造函数
--初始化类
Person = {name,age,gender,address = "china"}
--模拟方法
function Person:Show()
print(self.name,self.age,self.gender,self.address)
end
--模拟构造方法
function Person:New(name,age,gender,address)
--初始化一个新的表
local obj = {}
--把当前的表设置为新表的元表
--setmetatable(obj,Person)
setmetatable(obj,self)
--指定元表的index索引
--Person.__index = Person
self.__index = self
self.name = name
self.age = age
self.gender = gender
self.address = address
return obj
end
--实例化对象
--xiaoming = Person.New(Person)
xiaoming = Person:New()
xiaoming.name = "xiaoming"
xiaoming.age = 10
xiaoming:Show()
xiaohong = Person:New("xiaohong",20,"female","china")
xiaohong:Show()
print(xiaoming == xiaohong)
--输出
--[[
xiaoming 10 nil nil
xiaohong 20 female china
false
--]]
- Person:New()和Person.New(Person)效果一致,使用:是指第一个参数指定为:前的类
- setmetatable(obj,Person)和setmetatable(obj,self)效果相同,self是指是指第一个参数指定为:前的类,类似于其他语言中的this关键字
- Person.__index = Person是当查询主表不存在时,会调用元表的index参数,在指定的表中继续查询
- local obj = {}中obj只会在构造方法中使用,lua作用域默认为公开所以最好将其私有化
模拟继承、多态
--创造一个父类
Animal = {name}
--父类构造方法
function Animal:New(name)
local obj = {}
setmetatable(obj,self)
self.__index = self
self.name = name
return obj
end
--父类普通方法
function Animal:Sleep()
print(self.name.."睡觉")
end
--子类继承父类
Cat = Animal:New()
--子类构造方法
function Cat:New(name)
--子类构造方法和父类构造方法的不同点
local obj = Animal:New(name)
setmetatable(obj,self)
self.__index = self
self.name = name
return obj
end
--子类普通方法
function Cat:Eat(food)
print(self.name.."要吃"..food)
end
--子类多态
function Cat:Sleep()
print(self.name.."不睡觉")
end
--通过父类创建对象
tiger = Animal:New("老虎")
tiger:Sleep()
--通过子类创建对象
jjc = Cat:New("金渐层")
jjc:Eat("猫粮")
jjc:Sleep()
--输出
--[[
老虎睡觉
金渐层要吃猫粮
金渐层不睡觉
--]]
代码分离
--Animal.lua
Animal = {name,typeName}
function Animal:New(name,typeName)
local obj = {}
setmetatable(obj,self)
self.__index = self
self.name = name
self.typeName = typeName
return obj
end
function Animal:ToString()
print(self.name,self.typeName)
end
--Peson.lua
Person = {name,age,gender,address}
function Person:New(name,age,gender,address)
local obj = {}
setmetatable(obj,self)
self.__index = self
self.name = name
self.age = age
self.gender = gender
self.address = address
return obj
end
function Person:ToString()
print(self.name,self.age,self.gender,self.address)
end
--Person.lua
dofile("Animal.lua"
dofile("Person.lua")
jjc = Animal:New("金渐层","猫科动物")
jjc:ToString()
xiaoming = Person:New("小明",20,"男","中国")
xiaoming:ToString()
--输出
--[[
金渐层 猫科动物
小明 20 男 中国
--]]
- dofile若在同一个文件夹下,直接写需要加载的文件即可
- 不在同一个文件夹下,需要写相对路径或者绝对路径,绝对路径如果改变项目位置就会失效
- 相对路径:
-
class\\Animal.lua ..\\class\\Animal.lua
- 前者表示在当前路径下的class文件夹内
- 后者表示在当前路径上一级路径的class文件夹内
- require和dofile的区别
- 在加载一个.lua文件的时候,require会先在package.loaded中查找此模块是否存在,如果存在则直接返回模块,如果不存在,则加载此模块。
- dofile会对读入的模块编译执行,每调用dofile一次,都会重新编译执行一次。
- require的参数只是文件名,而dofile要求参数必须带上文件名的后缀。