1. 程式人生 > >Lua下通過元表模擬OOP程式設計,繼承多型

Lua下通過元表模擬OOP程式設計,繼承多型

Lua本身是沒有以明確的定義來支援OOP程式設計的,但是我們卻可以通過Lua核心提供的一些特性來間接實現簡單的面向物件的程式設計。 

通過Lua中的 table結構  metatable 以及函式可以配合實現OOP,以及繼承。這些說白了都是一種偽實現,不建議在Lua下使用多重繼承 。

在LUA中你想要 強制實現OOP 你必須需要懂一下幾個關鍵詞!!

什麼是語法糖?

語法糖即糖衣語法,C/C++升級過程中的面向物件 整體就是一種語法糖 ,是由英國電腦科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語,指計算機語言中新增的某種語法,這種語法對語言的功能並沒有影響,但是更方便程式設計師

使用。通常來說使用語法糖能夠增加程式的可讀性,從而減少程式程式碼出錯的機會。

比如char str[100] ;我訪問第一個 字元 我是不是可以這樣    str[1]   *(str+1) 簡化了 程式碼編寫 使粘合度 更高 就是一種語法糖。用過c#的人可以發現,C#的語法糖做到了極致。

什麼是table?

Lua中的結構只有table,他是基於 HashMap  與索引陣列與 一身,能存放任意型別資料,包括函式 何以其他表  這也就是  我們模擬整合的奠定了基礎。

什麼是metable?

local tb={["a"=1]}  這麼一段程式碼 ,假如 我print(tb.b) 那麼會提示找不到b, 

這個時候叫做元表的metable 就起作用了,這會觸發lua的 搜尋機制,就去從metatable 中 搜尋 b  這一點是不是和 javascript 的  prototype 型別呢?

這也就是我們實現繼承的基礎

 table中的__index是做什麼用的?

他是一個函式,這個函式告訴Lua直譯器  當在一個table中找不到  相對應元素的時候 如何從 metable 中搜索元素。

--語法糖 兩種等價操作 
--Class.__index=function(key)return Class[key] end 
--設定外部搜尋物件
Class.__index=Class 

--函式呼叫的語法糖等價操作 
  local a={}  
--lua中的函式預設都是有self傳遞進去的  語法糖會自動給我們傳遞 self
--也就是說通過.呼叫table的函式如果函式內部引用self 需要我們在呼叫的時候手動傳遞物件a進去 
--但是通過:呼叫的話 Lua直譯器 預設在每個函式呼叫給我們 吧 a給傳遞進去了  在函式內部引用 就叫做self
  a:b()== a.b(a)  

function SubClass:test()
    print("test is child ")
end
我們可以直接
SubClass.test(SubClass)
也可以 直接呼叫
SubClass:test() 

實現OOP

--模擬實現OOP
--通過table定義類模型
Class={}   
--語法糖 實際上被轉換為   
--Class.__index=function(key)return Class[key] end 
--設定外部搜尋物件
Class.__index=Class 
function Class:new(x)      --語法糖而已
   print('模擬建構函式!')
   local temObj={}
   temObj.x=x 
   --設定meta object 
   setmetatable(temObj,self)
   return  temObj
end

function Class:ShowData()
    print("self.x:",self.x)
end

function Class:delete()
   self.x=nil
   print('模擬解構函式!') 
end

local clsObj=Class:new(1)
--隱式傳遞clsObj作為 self 引數 
clsObj:ShowData()
--顯示傳參作為self引數
clsObj.ShowData(clsObj)
clsObj:delete()
結果如下

LUA模擬實現繼承

--模擬實現OOP
--通過table定義類模型
Class={}   
--語法糖 實際上被轉換為   
--Class.__index=function(key)return Class[key] end 
--設定外部搜尋物件
Class.__index=Class 
function Class:new() 
   print('模擬建構函式!')
   local temObj={}
   --設定meta object 
   setmetatable(temObj,self)
   return  temObj
end

function Class:parent()
    print("parent is ",type(self))
end

function Class:delete()
   print('模擬解構函式!') 
end

--從基類建立物件 
SubClass=Class:new() 
--設定__index搜尋 範圍 
SubClass.__index=SubClass
--派生建構函式
function SubClass:new()
  local obj={}
--設定派生metable為self 就是 SubClass
  setmetatable(obj,self)
--返回物件
  return obj
end
---派生物件方法
function SubClass:child()
    print("child is ",type(self))
end

--建立一個派生物件
local  obj=SubClass:new()
--通過語法糖呼叫不同方法 
obj:child()
obj:parent()
--語法糖等價於
obj.child(obj)
obj.parent(obj)

模擬實現多型

既然繼承我們都實現了 多型我們只需要在不同的型別中新增不同的定語法糖函式義即可

--模擬實現多型
Class={}   
--語法糖 實際上被轉換為   
--Class.__index=function(key)return Class[key] end 
--設定外部搜尋物件
Class.__index=Class 
function Class:new() 
   print('基類模擬建構函式!')
   local temObj={}
   --設定meta object 
   setmetatable(temObj,self)
   return  temObj
end
--
function Class:test()
    print("test is parent")
end


--從基類建立物件 
SubClass=Class:new() 
--設定__index搜尋 範圍 
SubClass.__index=SubClass
--派生建構函式
function SubClass:new()
  local obj={}
--設定派生metable為self 就是 SubClass
  setmetatable(obj,self)
--返回物件
  return obj
end
--override方法
function SubClass:test()
    print("test is child ")
end
--建立一個派生物件
local  objChild=SubClass:new()
--建立一個基類物件
local parentObj=Class:new()
parentObj:test();
objChild:test();


參考資料 

http://blog.csdn.net/ym012/article/details/7206968

http://www.xuebuyuan.com/1613223.html

http://blog.csdn.net/xocoder/article/details/9028347

http://www.cnblogs.com/zhiranok/archive/2012/02/07/lua_object_skill.html