【游戲開發】在Lua中實現面向對象特性——模擬類、繼承、多態


一、簡介

  Lua是一門非常強大、非常靈活的腳本語言,自它從發明以來,無數的游戲使用了Lua作為開發語言。但是作為一款腳本語言,Lua也有着自己的不足,那就是它本身並沒有提供面向對象的特性,而游戲開發是一項龐大復雜的工程,如果沒有面向對象功能勢必會為開發帶來一定的不便。不過幸好Lua中有table這樣強大的數據結構,利用它再結合元表(metatable),我們便可以很方便地在Lua中模擬出類、繼承和多態等面向對象編程具有的特性。

二、前提知識

  按照慣例,我們還是先來熟悉一下必要的前提知識,以便方便我們理解后續的代碼。

1.表(table)

  (1)table 是 Lua 的一種數據結構,用於幫助我們創建不同的數據類型,如:數組、字典等;

  (2)table 是一個關聯型數組,你可以用任意類型的值來作數組的索引,但這個值不能是 nil,所有索引值都需要用 "["和"]" 括起來;如果是字符串,還可以去掉引號和中括號; 即如果沒有[]括起,則認為是字符串索引,Lua table 是不固定大小的,你可以根據自己需要進行擴容;

  (3)table 的默認初始索引一般以 1 開始,如果不寫索引,則索引就會被認為是數字,並按順序自動從1往后編;

  (4)table 的變量只是一個地址引用,對 table 的操作不會產生數據影響;

  (5)table 不會固定長度大小,有新數據插入時長度會自動增長;

  (6)table 里保存數據可以是任何類型,包括function和table;

  (7)table所有元素之間,總是用逗號 "," 隔開;

2.元表(metatable)

  關於元表的概念以及它的要點,我們已經在《【游戲開發】小白學Lua——從Lua查找表元素的過程看元表、元方法》這篇博客中做了深入地探討,在此就不再贅述了,忘記了或者不熟悉的小伙伴可以去看一下。

三、Lua中實現類、繼承、多態

1.利用Lua實現類

  在面向對象的特性中,類一般都有類名,構造方法,成員方法,屬性等。下面我們就用Lua中的table和元表實現一下模擬類中的這些特性,Class.lua 代碼如下:

 1 --類的聲明,這里聲明了類名還有屬性,並且給出了屬性的初始值
 2 Class = {x=0,y=0}
 3 --設置元表的索引,想模擬類的話,這步操作很關鍵
 4 Class.__index = Class
 5 --構造方法,構造方法的名字是隨便起的,習慣性命名為new()
 6 function Class:new(x,y)
 7      local self = {}  --初始化self,如果沒有這句,那么類所建立的對象如果有一個改變,其他對象都會改變
 8      setmetatable(self, Class)  --將self的元表設定為Class
 9      self.x = x   --屬性值初始化
10      self.y = y
11      return self  --返回自身
12 end
13 
14 --這里定義類的其他方法
15 function Class:test()
16  print(self.x,self.y)
17 end
18 
19 function Class:plus()
20  self.x = self.x + 1
21  self.y = self.y + 1
22 end

  簡單解釋一下,在Lua中的類,其實都是table,因為table既可以存儲普通變量又可以存儲函數或者另一個table,利用這個特性,我們實現了面向對象的類中的方法、屬性(字段)和構造方法。而設置元表和__index元方法這一步也是必不可少的,我們需要借助它的查找機制來實現類的繼承和多態等。

2.利用Lua實現繼承

  在上面我們實現了Lua中的類,那么實現繼承也就不是什么難事了,SubClass.lua 代碼如下:

 1 require 'Class'
 2 
 3 --聲明了新的屬性Z  
 4 SubClass = {z = 0}  
 5 --設置元表為Class  
 6 setmetatable(SubClass, Class)  
 7 --還是和類定義一樣,表索引設定為自身  
 8 SubClass.__index = SubClass  
 9 --這里是構造方法
10 function SubClass:new(x,y,z)  
11    local self = {}             --初始化對象自身  
12    self = Class:new(x,y)       --將對象自身設定為父類,這個語句相當於其他語言的super ,可以理解為調用父類的構造函數 
13    setmetatable(self, SubClass)    --將對象自身元表設定為SubClass類  
14    self.z= z                   --新的屬性初始化,如果沒有將會按照聲明=0  
15    return self  
16 end  
17 
18 --定義一個新的方法  
19 function SubClass:go()  
20    self.x = self.x + 10  
21 end  
22 
23 --重定義父類的方法,相當於override
24 function SubClass:test()  
25      print(self.x,self.y,self.z)  
26 end  

  代碼里面的注釋已經很全了,關鍵點是通過設置SubClass的元表為它的父類Class,從而很方便地實現了繼承,這還是要歸功於table的查找機制。在子類SubClass中,我們可以自由地新增字段和子類獨有的新方法。而且還可以重定義或者說覆蓋/重寫父類的方法,類似於Java中的override,子類覆蓋父類的虛方法。有了這些我們就可以模擬面向對象中的多態了。

3.利用Lua實現多態

  這里我們新建一個 Main.lua 將它作為我們程序的入口,在里面測試一下我們上面的代碼是否如我們所期待的那樣,Main.lua 代碼如下:

 1 require 'Class'
 2 require 'SubClass'
 3 
 4 local a = Class:new() -- 首先實例化父類的對象,並調用父類中的方法
 5 a:plus()
 6 a:test()
 7 
 8 a = SubClass:new()    -- 然后實例化子類對象
 9 a:plus()            -- 子類對象可以訪問到父類中的成員和方法
10 a:go()                -- 子類對象調用子類中的新增方法
11 a:test()            -- 子類對象調用重寫的方法

  程序運行的輸出結果如下:

1       1
11      1       0

  首先我們實例化父類對象並調用父類中的方法,結果輸出了1 1,符合預期。接着我們再實例化了子類的對象,然后成功地訪問到了父類中的成員變量和方法,並且還可以訪問子類中的新增方法,最后我們再執行了重寫過父類中虛函數的方法,結果輸出 11 1 0,也是正確的。

四、總結

  通過簡單地幾步,我們就在Lua中成功地模擬了類、繼承和多態的特性,這可以給我們程序開發帶來了不少的方便。以Unity游戲開發舉例,tolua/ulua是Unity游戲開發熱更新方案中的一種,他們功能很強大,但是美中不足的一點就是它們沒有提供面向對象的特性,所以在開發的時候,很多直接就是全局函數、全局變量和過程式的開發流程,影響了開發的效率,更對之后的維護帶來諸多不便。因此我們就可以通過與本篇中類似的方法,改進tolua/ulua,讓它們也可以實現面向對象開發。當然本篇中的代碼只是作為拋磚引玉,它其實是十分簡陋的,想用在商業項目中還需要做很多的改良與完善。至於如何改進tolua/ulua,讓他們支持面向對象特性,我們將在以后的篇章中繼續探討。

   本篇博客中的代碼已經同步到Github:https://github.com/XINCGer/Unity3DTraining/tree/master/SomeTest/Lua_Class   歡迎fork!

 

 

作者:馬三小伙兒
出處:http://www.cnblogs.com/msxh/p/8469340.html 
請尊重別人的勞動成果,讓分享成為一種美德,歡迎轉載。另外,文章在表述和代碼方面如有不妥之處,歡迎批評指正。留下你的腳印,歡迎評論!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM