Lua中的OOP

前言

lua的oop和table密切相关,整个OOP都是通过table来模拟的,继承和重写用到了元表。

正文

先按照常规的table结构定义一个武器类,武器名称,威力,子弹数量

1
2
3
4
5
Weapon = {
id = "",
damage=0,
bulletCount=0,
}

定义构造方法,这样可以new出各种类型的武器,这里的New对应的是一个函数而不是某个字段,用来模拟构造函数

1
2
3
4
5
6
7
8
9
10
11
12
Weapon = {
id = "",
damage=0,
bulletCount=0,
New = function(id,damage,bulletCount)
local w ={} --构造一个新表
w.damage = damage or 0
w.bulletCount = bulletCount or 0
w.id = id or ""
return w
end,
}

再加上一个可以显示武器信息的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Weapon = {
id = "",
damage=0,
bulletCount=0,
New = function(id,damage,bulletCount)
local w ={}
w.damage = damage or 0
w.bulletCount = bulletCount or 0
w.id = id or ""
w.ShowInfo = Weapon.ShowInfo --新的表内依然要定义方法
return w
end,
ShowInfo = function(self)
print("名字:",self.id.."\t","伤害:",self.damage.."\t","弹药数:",self.bulletCount)
end
}

这里模拟出来的Weapon就是一个工厂,通过不断的调用New方法可以产生新的实例

1
2
3
4
p = Weapon.New("98k",80,12)
p2 = Weapon.New("m4",20,30)
p:ShowInfo() --名字: 98k 伤害: 80 弹药数: 12
p2:ShowInfo() --名字: m4 伤害: 20 弹药数: 30

还可以结合元表来做一些运算符操作,其他部分代码一样,只是添加了元表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Weapon = {
id = "",
damage=0,
bulletCount=0,
mt = {} ,--元表
New = function(id,damage,bulletCount)
local w ={}
setmetatable(w,Weapon.mt) --设置元表
w.damage = damage or 0
w.bulletCount = bulletCount or 0
w.id = id or ""
w.ShowInfo = Weapon.ShowInfo
w.mt = Weapon.mt --链接元表方法
return w
end,
ShowInfo = function(self)
print("名字:",self.id.."\t","伤害:",self.damage.."\t","弹药数:",self.bulletCount)
end
}
p = Weapon.New("98k",80,12)
p2 = Weapon.New("m4",20,30)
p:ShowInfo() --名字: 98k 伤害: 80 弹药数: 12
p2:ShowInfo() --名字: m4 伤害: 20 弹药数: 30
--比较是否为同一种武器
Weapon.mt.__eq = function(w1,w2)
return w1.id == w2.id and w1.damage == w2.damage
end
print(p==p2) --false 比较结果

同理,如果乐意的话,可以加上add,sub….之类的,也可以重写__tostring

既然使用了元表来模拟oop,不如再进一步充分利用,通过设置元方法,可以省去很多操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Weapon = {
id = "",
damage=0,
bulletCount=0,
mt = {} ,--元表
New = function(id,damage,bulletCount)
local w ={}
setmetatable(w,Weapon.mt) --设置元表
w.damage = damage or 0
w.bulletCount = bulletCount or 0
w.id = id or ""
--通过__index 设置,免去手动链接
--w.ShowInfo = Weapon.ShowInfo
--w.mt = Weapon.mt --链接元表方法
return w
end,
ShowInfo = function(self)
print("名字:",self.id.."\t","伤害:",self.damage.."\t","弹药数:",self.bulletCount)
end
}
--比较是否为同一种武器
Weapon.mt.__eq = function(w1,w2)
return w1.id == w2.id and w1.damage == w2.damage
end
Weapon.mt__index = Weapon --设置__index
p = Weapon.New("98k",80,12)
p2 = Weapon.New("m4",20,30)
p:ShowInfo() --名字: 98k 伤害: 80 弹药数: 12
p2:ShowInfo() --名字: m4 伤害: 20 弹药数: 30
print(p==p2) --false 比较结果

模拟继承和方法重写,在上面Weapon类的基础上,构造一个SuperWeapon继承于Weapon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SuperWeapon={
ExplosionRange = 200, --新增字段,爆炸范围
mt = {}, --依然是元表,用来提供和方法的链接
New = function(id,damage,bulletCount,range)
local s = {}
s = Weapon.New(id,damage,bulletCount) --id之类的字段保留,模拟继承自父类Weapon
setmetatable(s,SuperWeapon.mt) --定义元表
s.ExplosionRange = range
return s
end,
ShowInfo = function(self)
print("名字:",self.id.."\t","伤害:",
self.damage.."\t","弹药数:",self.bulletCount.."\t",
"爆炸范围:",self.ExplosionRange)
end,
}
SuperWeapon.mt.__index = SuperWeapon --链接元表
sp = SuperWeapon.New("RPG",500,3,400)
sp:ShowInfo() --名字: RPG 伤害: 500 弹药数: 3 爆炸范围: 400

在设置__index元方法处可以简化一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SuperWeapon={
ExplosionRange = 200, --新增字段,爆炸范围
New = function(id,damage,bulletCount,range)
local s = {}
s = Weapon.New(id,damage,bulletCount) --id之类的字段保留,模拟继承自父类Weapon
setmetatable(s,{__index = SuperWeapon}) --定义元表
s.ExplosionRange = range
return s
end,
ShowInfo = function(self)
print("名字:",self.id.."\t","伤害:",
self.damage.."\t","弹药数:",self.bulletCount.."\t",
"爆炸范围:",self.ExplosionRange)
end,
}
sp = SuperWeapon.New("RPG",500,3,400)
sp:ShowInfo() --名字: RPG 伤害: 500 弹药数: 3 爆炸范围: 400