面向對象編程技術是目前最常用的編程技術之一。目前大量的編程語言都支持面向對象的特性:
-類(class):類是可以創(chuàng)建對象,并為狀態(tài)(成員變量)提供初值及行為實現(xiàn)的可擴展模板。 -對象(objects):對象是類的實例,每個對象都有獨立的內存區(qū)域。 -繼承(inheritance):繼承用于描述一個類的變量和函數(shù)被另一個類繼承的行為。 -封裝(encapsulation):封裝是指將數(shù)據和函數(shù)組織在一個類中。外部可以通過類的方法訪問內中的數(shù)據。封裝也被稱之為數(shù)據抽象。
在 Lua 中,我們可以使用表和函數(shù)實現(xiàn)面向對象。將函數(shù)和相關的數(shù)據放置于同一個表中就形成了一個對象。繼承可以用元表實現(xiàn),它提供了在父類中查找存在的方法和變量的機制。
Lua 中的表擁有對象的特征,比如狀態(tài)和獨立于其值的標識。兩個有相同值的對象(表)是兩個不同的對象,但是一個對象在不同的時間可以擁有不同的值。與對象一樣,表擁有獨立于其創(chuàng)建者和創(chuàng)建位置的生命周期。
面向對象已經是一個廣泛使用的概念,但是你需要正確清楚地理解它。
讓我們看一個數(shù)學方面的例子。我們經常需要處理各種形狀,比如圓、矩形、正方形。
這些形狀有一個共同的特征——面積。所以,所有其它的形狀都可以從有一個公共特征——面積的基類擴展而來。每個對象都可以有它自己的特征和函數(shù),比如矩陣有屬性長、寬和面積,printArea 和 calculateArea 方法。
下面例子實現(xiàn)了矩陣類的三個屬性:面積、長和寬。它還同時實現(xiàn)了輸出面積的函數(shù) printArea。
-- 元類
Rectangle = {area = 0, length = 0, breadth = 0}
-- 繼承類的方法 new
function Rectangle:new (o,length,breadth)
o = o or {}
setmetatable(o, self)
self.__index = self
self.length = length or 0
self.breadth = breadth or 0
self.area = length*breadth;
return o
end
-- 繼承類的方法 printArea
function Rectangle:printArea ()
print("The area of Rectangle is ",self.area)
end
創(chuàng)建對象即是為類的實例分配內存空間的過程。每個對象都有自己獨立的內存區(qū)域,同時還會共享類的數(shù)據。
r = Rectangle:new(nil,10,20)
我們可以使用點操作符訪問類中屬性。
print(r.length)
使用冒號操作符可以訪問對象的成員方法,如下所示:
r:printArea()
初始化階段,調用函數(shù)為對象分配內存同時設置初值。這與其它與面向對象的語言中的構造器很相似。其實,構造器本身也就和上面的初始化代碼一樣,并沒有什么特別之處。
讓我們一起看一個 Lua 實現(xiàn)面向對象的完整例子。
-- 元類
Shape = {area = 0}
-- 基類方法 new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- 基類方法 printArea
function Shape:printArea ()
print("The area is ",self.area)
end
-- 創(chuàng)建對象
myshape = Shape:new(nil,10)
myshape:printArea()
運行上面的程序,我們可以得到如下的輸出結果:
The area is 100
繼承就是從基對象擴展的過程,正如從圖形擴展至矩形、正方形等等。在現(xiàn)實世界中,常用來共享或擴展某些共同的屬性和方法。
讓我們看一個簡單的類擴展的例子。我們有如下的類:
-- 元類
Shape = {area = 0}
-- 基類方法 new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- 基類方法 printArea
function Shape:printArea ()
print("The area is ",self.area)
end
我們從上面的類中擴展出正方形類,如下所示:
Square = Shape:new()
-- 繼承類方法 new
function Square:new (o,side)
o = o or Shape:new(o,side)
setmetatable(o, self)
self.__index = self
return o
end
繼承類可以重寫基類的方法,從而根據自己的實際情況實現(xiàn)功能。示例代碼如下所示:
-- 繼承方法 printArea
function Square:printArea ()
print("The area of square is ",self.area)
end
在元表的幫助下,我們可以使用新的 new 方法實現(xiàn)類的擴展(繼承)。子類中保存了所有基類的成員變量和方法。
-- Meta class
Shape = {area = 0}
-- Base class method new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- Base class method printArea
function Shape:printArea ()
print("The area is ",self.area)
end
-- Creating an object
myshape = Shape:new(nil,10)
myshape:printArea()
Square = Shape:new()
-- Derived class method new
function Square:new (o,side)
o = o or Shape:new(o,side)
setmetatable(o, self)
self.__index = self
return o
end
-- Derived class method printArea
function Square:printArea ()
print("The area of square is ",self.area)
end
-- Creating an object
mysquare = Square:new(nil,10)
mysquare:printArea()
Rectangle = Shape:new()
-- Derived class method new
function Rectangle:new (o,length,breadth)
o = o or Shape:new(o)
setmetatable(o, self)
self.__index = self
self.area = length * breadth
return o
end
-- Derived class method printArea
function Rectangle:printArea ()
print("The area of Rectangle is ",self.area)
end
-- Creating an object
myrectangle = Rectangle:new(nil,10,20)
myrectangle:printArea()
運行上面的程序,我們可以得到如下的輸出結果:
The area is 100
The area of square is 100
The area of Rectangle is 200
上面的例子中,我們繼承基類 Shape 創(chuàng)建了兩個子類 Rectange 與 Square。在子類中可以重寫基類提供的方法。在這個例子中,子類重寫了 printArea 方法。