1. 程式人生 > >Lua面向對象編程

Lua面向對象編程

使用 修改 存在 類繼承 自己的 特征 這一 dex 自身

面向對象的三個基本特征

  1. 封裝:隱藏對象的屬性和實現細節,僅對外公開接口,控制在程序中屬性的讀和修改的訪問級別。
  2. 繼承:使子類具有父類的屬性、方法或者重新定義、追加屬性和方法等。
  3. 多態:同以操作作用於不同的對象,可以有不同的解釋,產生不同的執行結果。在運行時,可以通過指向基類的指針,來調用實現派生類的方法。


Lua中的面向對象

Lua中的表和對象有很多相似性,因此在Lua中可以使用表來實現面向對象。
Lua中類的方法可以通過表+function來模擬

zhangsan = {name = ""}

function zhangsan.setName(self, name)
    self.name = name
end

zhangsan.setName(zhangsan, "張三")
print(zhangsan.name)

--輸出:
--張三


類(Class)

上面的例子中,zhangsan對象擁有了屬性和方法,但是這個對象卻不是通過類來創建的。在大多數面向對象的語言中都提供了類的概念,類在對象創建中扮演了模板的作用。
在Lua中,我們可以使用原型的思想來模擬類。讓每一個對象都有一個原型,當對象遇到未知的操作時就在原型中去查找。
如下,為zhangsan指定它的原型Person:

Person = {}
function Person.setName(self, name)
    self.name = name
end

function Person:new(person)
    person = person or {}
    self.__index = self
    setmetatable(person, self)
    return person
end

zhangsan = Person:new()
print(zhangsan.name)

zhangsan:setName("張三")
print(zhangsan.name)

--輸出:
--nil
--張三

在上面的代碼中,使用了冒號:來操作,如Person:new(person)這樣的寫法相當於Person.new(Person, person),冒號只是一個語法糖,這個函數中的self即為Person類本身。


繼承

在類(Class)的new操作中,self.__index = self,將Person的元方法__index指向了自身,這樣做會導致當調用一個方法時,解釋器第一時間將會查找Person自身有沒有這個方法。這一點和繼承很相似。
在繼承中,子類可以擁有父類的屬性和方法,也可以定義自己的屬性和方法。
如果要從一個類中派生一個子類,可以先創建一個從基類繼承了所有操作的空類:

Male = Person:new()
Male.sex = "男"

zhangsan = Male:new()
zhangsan:setName("張三")
print(zhangsan.name, zhangsan.sex)

--輸出:
--張三    男

Male擁有了Person的new方法,同時通過Male創建的zhangsan擁有Person的setName方法。
在這個過程中,Male = Person:new()會將Male的元表設置為Person,zhangsan = Male:new()則將zhangsan的元表設置為了Male。
當調用zhangsan:setName時,Lua將首先從zhangsan查找setName方法,發現不存在時,則從zhangsan元表Male的元方法__index中(即Male本身)查找,直到在Person中找到該方法。因此,zhangsan不僅有Male的sex屬性,還擁有Person的setName方法。
同時,還可以很方便地在Male中重寫Person的setName方法,只需要定義一個新方法即可。

function Male:setName(name)
    self.name = "Male:"..name
end

zhangsan = Male:new()
zhangsan:setName("張三")
print(zhangsan.name)

--輸出:
--Male:張三

這是由於,在Male中已經有setName方法了,所以解釋器不會再去Person中去查找。


Lua面向對象編程