阅读本文需要理解前一篇文章Lua中的元方法
使用特定的对象的弊端
Account = {balance = 0}
function Account.withdraw(v)
Account.balance = Account.balance - v
end
在函数中使用全局名称Account很糟糕
首先,这个函数只能针对特定的对象工作
即使针对特定的对象,这个函数也只有在对象保存在特定的全局变量中才能工作。
如果我们改变了对象的名称,whitdraw就不能工作了
a,Account = Account,nil
a.withdraw(100) --Error
这种行为违反了对象拥有独立生命周期的原则
使用self或this额外的参数
冒号操作符
当通过:调用时,系统会自动传递当前的table给self,例如a.eat(a)相当于a:eat()
传递当前对象给eat方法,这样就提高了table的方法的扩展性了。
-- 本质是使用table进行模拟
--定义空表,相当于是一个类
Person = {}
---定义局部表引用变量,降低方法引用表字段的耦合性
this =Person
--定义字段
Person.Name="Bob"
Person.Gender = "男"
Person.Age = 18
--定义方法
--第一种第一方式(匿名函数)
Person.Speak = function()
print("人在说话")
end
--第二种
function Person.Walking()
print("人在走路")
end
--方法中调用方法
function Person:showInfo()
print("调用个人信息")
print("Name:"..this.Name)
print("Age:"..this.Age)
end
--冒号操作符,隐藏了一个self参数
function Person:show()
print("调用个人信息")
print("Name:"..self.Name)
print("Age:"..self.Age)
end
--调用
print(Person.Name)
print(Person.Gender)
print(Person.Age)
Person.Speak()
Person.Walking()
a = Person
Person = nil
a.showInfo()
--相当于a.showInfo(a)
a:showInfo()
New新对象
使用self我们解决了表的方法的通用性问题,但我们想解决创建一个新的Person表对象,又得重写一个表,重新赋值,非常麻烦。所以在Lua中我们先定义好一个原型,通过定义一个new方法,可以很方便的创建一个原型对象(在Lua中还是一个表)。
Player = {
x = 0, y = 0,
name = "",
new = function ()
p = {}
for k,v in pairs(Player) do
p[k] = v
end
return p
end,
--错误示范一
--move = function(x,y)
-- Player.x = Player.x + x
-- Player.y = Player.y +y
--end
--方法一
--[[ move = function(p,x,y)
p.x = p.x+x
p.y = p.y +y
end]]
}
--方法二 self要配合“:”使用
function Player:move(x,y)
self.x = self.x +x
self.y = self.y +y
end
p1 = Player.new()
p1.x = 10;
p1.y = 20;
p1.name = "Bob"
p2 = Player.new()
p2.x = 30;
p2.y = 40;
p2.name = "Steve"
print(p1.x,p1.y,p1.name)
print(p2.x,p2.y,p2.name)
--这里表示了“:”的意思,把本身当做参数传递进去
p1:move(10,10)
p2:move(10,10)
print(p1.x,p1.y,p1.name)
print(p2.x,p2.y,p2.name)
方式二:使用到元表
通过__index方法,当表中没有查找到key值时,就会去元表中查找。
function Account:new(obj)
obj = obj or {}
self.__index = self
setmetatable(obj,self)
return obj
end
三、使用到继承
使用new方法创建一个实例对象,然后对这个实例继续调用new方法。然后这个实例就像继承其他方法一样继承了基类的new方法。不过现在执行new方法,它的self参数是自己。
Person = {
name = 0;
age = 0;
New = function(name, age)
local tab = {}
setmetatable(tab, Person)
tab.name = name
tab.age = age
return tab
end;
ToString = function(self)
print(self.name, self.age)
end;
Work = function(self)
print(self.name .. "的工作是养老")
end;
}
---这句话放在外表确保先执行 重建Person
Person.__index = Person;
father= Person.New("yeye", 99)
father:ToString()
father:Work()
print(getmetatable(father).name)
son = father.New("son",18)
son:ToString()
son:Work()
--son son中含有Work方法 就会直接返回
function son:Work()
print(self.name.."我的工作是开车")
end
son:Work()
print(getmetatable(son).name)
四、多态
Lua天然是多态,一个table没有固定的类型,它的指针指向谁,调用的就是谁的对象。
a= Account:new();
a= spacialAccount:new()
a:display() 调用的是子类的
Account.display(a) 调用的是父类的 以静态的方式调用