在lua原生語(yǔ)法特性中是不具備面向?qū)ο笤O(shè)計(jì)的特性夺溢。因此浩嫌,要想在lua上像其他高級(jí)語(yǔ)言一樣使用面向?qū)ο蟮脑O(shè)計(jì)方法有以下兩種選擇:一種是使用原生的元表(metatable)來(lái)模擬面向?qū)ο笤O(shè)計(jì)闻牡,另外一種則是使用第三方框架LuaScriptoCore來(lái)實(shí)現(xiàn)。下面將逐一講解這兩種方式的實(shí)現(xiàn)過(guò)程(以下內(nèi)容將基于Lua 5.3版本進(jìn)行闡述)句狼。
1. 元表方式
1.1 關(guān)于元表(metatable)
在lua中每種類型變量都可以有一個(gè)元表岗宣,而元表實(shí)際上是一個(gè)table
,它用于定義原始值在特定操作下的行為转捕。如果想改變一個(gè)變量在特定操作下的行為作岖,則可以在它的元表中設(shè)置對(duì)應(yīng)元方法(metamethod)。換種說(shuō)法五芝,元表就是一個(gè)變量鉤子痘儡,用來(lái)鉤取變量的底層處理方法(即元方法),然后改寫這些方法的處理行為枢步。
其中元方法如下面表格所示:
元方法 | 說(shuō)明 |
---|---|
__index | 當(dāng)訪問變量某個(gè)key時(shí)沉删,如果沒有對(duì)應(yīng)的value,則會(huì)訪問元表__index 元方法所指定的對(duì)象醉途。如果指定值為table 類型矾瑰,則會(huì)訪問該table 的key所對(duì)應(yīng)的值;如果指定值為function 類型隘擎,則該方法返回值作為對(duì)應(yīng)key的值 |
__newindex | 當(dāng)設(shè)置變量的某個(gè)key時(shí)殴穴,如果沒有對(duì)應(yīng)的key,則會(huì)訪問元表__newindex 元方法來(lái)處理鍵值設(shè)置 |
__add | 當(dāng)兩個(gè)變量進(jìn)行加法操作時(shí)觸發(fā)货葬,如:var1 + var2
|
__sub | 當(dāng)兩個(gè)變量進(jìn)行減法操作時(shí)觸發(fā)采幌,如:var1 - var2
|
__mul | 當(dāng)兩個(gè)變量進(jìn)行乘法操作時(shí)觸發(fā),如:var1 * var2
|
__div | 當(dāng)兩個(gè)變量進(jìn)行除法操作時(shí)觸發(fā)震桶,如:var1 / var2
|
__mod | 當(dāng)兩個(gè)變量進(jìn)行取模操作時(shí)觸發(fā)休傍,如:var1 % var2
|
__unm | 當(dāng)變量進(jìn)行取反操作時(shí)觸發(fā),如:~var
|
__pow | 當(dāng)變量進(jìn)行冪操作時(shí)觸發(fā)蹲姐,如:var^2
|
__concat | 當(dāng)兩個(gè)變量進(jìn)行連接時(shí)觸發(fā)磨取,如:var1 .. var2
|
__eq | 當(dāng)兩個(gè)變量判斷是否相等時(shí)觸發(fā),如:var1 == var2
|
__lt | 當(dāng)一個(gè)變量判斷是否小于另一個(gè)變量時(shí)觸發(fā)淤堵,如:var1 < var2
|
__le | 當(dāng)一個(gè)變量判斷是否小于或等于另一個(gè)變量時(shí)觸發(fā)寝衫,如: var1 <= var2` |
__call | 當(dāng)變量被用作方法調(diào)用時(shí)觸發(fā)顷扩,一般來(lái)說(shuō)function 類型是允許被調(diào)用的拐邪,對(duì)于其他類型默認(rèn)是不能進(jìn)行調(diào)用的,那么該元方法的作用就是讓你的變量能夠像function 一樣被調(diào)用 |
__tostring | 當(dāng)使用tostring 轉(zhuǎn)換變量為字符串或者調(diào)用print 進(jìn)行打印時(shí)觸發(fā)隘截,如:local t = {}; print (t);
|
__gc | 當(dāng)變量被回收時(shí)觸發(fā)扎阶。 |
__mode | 當(dāng)設(shè)置table 為弱引用table 時(shí)使用汹胃。弱引用table 可以讓保存的key或者value為弱引用狀態(tài),方便GC標(biāo)記和回收(如果非弱引用情況下东臀,必須要table被回收時(shí)着饥,其內(nèi)部的key和value才允許GC回收)。 |
元表的設(shè)置基本分為三個(gè)步驟:
- 先創(chuàng)建一個(gè)作為元表的
table
- 設(shè)置需要實(shí)現(xiàn)的元方法惰赋。
- 使用
setmetatable
方法將元表綁定到變量中宰掉。
實(shí)現(xiàn)代碼如下:
-- 創(chuàng)建元表并設(shè)置元方法
local mt = {};
mt.__index = function (table, key)
return "Hello Metatable!";
end
-- 創(chuàng)建實(shí)例并綁定元表
local t = {};
setmetatable(t, mt);
上面的元方法在本篇文章中不會(huì)一一細(xì)說(shuō),在后面的章節(jié)會(huì)針對(duì)面向?qū)ο笮枰褂玫?code>__index赁濒、__newindex
轨奄、__call
、__gc
拒炎、__tostring
這幾個(gè)元方法進(jìn)行舉例說(shuō)明挪拟。
為了幫助大家理解如何實(shí)現(xiàn)lua的面向?qū)ο螅旅娴恼鹿?jié)會(huì)逐步地構(gòu)建面向?qū)ο笏枰奶匦曰髂悖暾匮菔菊麄€(gè)演化過(guò)程玉组。廢話不多說(shuō),直接開干~
1.2 類型聲明
在開始構(gòu)建類型前丁侄,我們先為面向?qū)ο笤O(shè)想一些基本的規(guī)則惯雳,這樣可以避免后面參與擴(kuò)展和開發(fā)的人因?yàn)槔斫獾牟灰粯樱瑢?dǎo)致整個(gè)結(jié)構(gòu)的規(guī)則混亂和不一致鸿摇。根據(jù)需要我們先設(shè)定如下幾點(diǎn):
- 類型名稱首字母必須大寫
- 類型必須為全局的變量
- 類型必須使用
__index
元方法指向自身 - 類型必須使用
__gc
元方法進(jìn)行銷毀時(shí)的操作 - 類型的屬性必須使用點(diǎn)語(yǔ)法進(jìn)行聲明和訪問
- 類型的類方法和實(shí)例方法聲明和調(diào)用必須使用冒號(hào)(:)語(yǔ)法聲明吨凑,目的讓方法都帶有一個(gè)默認(rèn)的
self
參數(shù) - 類型的構(gòu)造方法命名為
create
,并且為類方法
根據(jù)上面的約定户辱,我們先來(lái)定義一個(gè)所有對(duì)象的基類Object
:
-- 聲明類型
Object = {};
-- 設(shè)置__index元方法
Object.__index = Object;
-- 設(shè)置__gc元方法
Object.__gc = function (instance)
-- 進(jìn)行對(duì)象銷毀工作
print(instance, "destroy");
end
-- 定義構(gòu)造函數(shù)
function Object:create()
local instance = {};
setmetatable(instance, self);
return instance;
end
-- 定義實(shí)例方法
function Object:toString()
print (tostring(self));
end
可以看到我們創(chuàng)建了一個(gè)全局的table
變量Object
來(lái)作為類型鸵钝。
然后使用了元方法__index
進(jìn)行自身指向,這樣做的目的是使實(shí)例對(duì)象能夠訪問對(duì)象所定義的屬性或者方法庐镐。因?yàn)?code>__index的特點(diǎn)是當(dāng)變量訪問指定不存在的key時(shí)恩商,就會(huì)去調(diào)用其元表的__index
方法,由于__index
指向就是Object
必逆,因此就會(huì)判斷Object
是否存在該key怠堪,并進(jìn)行返回。另外如果指向的對(duì)象也設(shè)置了元表并且使用了__index
名眉,那么會(huì)繼續(xù)尋找其元表的__index
指向粟矿,直到最終沒有設(shè)置元表的對(duì)象(這個(gè)特性在實(shí)現(xiàn)繼承時(shí)特別關(guān)鍵,并且效果很好)损拢。具體找尋方式如下圖所示:
元方法__gc
在這里也使用到了陌粹,利用其特性可以輕松地知道對(duì)象實(shí)例銷毀時(shí)機(jī),可以在方法里面進(jìn)行一些后續(xù)的處理福压,類似C++中的析構(gòu)函數(shù)掏秩。在這里只是簡(jiǎn)單地打印是哪個(gè)對(duì)象被銷毀或舞。
接著我們講解一下構(gòu)造方法create
的實(shí)現(xiàn),方法中調(diào)用了setmetatable
方法將self
(即類型Object
)元表綁定到instance
這個(gè)變量蒙幻,配合之前設(shè)置__index
元方法映凳,實(shí)例變量就會(huì)擁有與Object
相同的一些屬性和方法定義了。
toString
方法則是一個(gè)實(shí)例方法邮破, 主要用于將對(duì)象轉(zhuǎn)換成字符串诈豌。
該類型具體使用方法如下所示:
local obj = Object:create();
print(obj:toString());
冒號(hào)(:)是lua的語(yǔ)法糖,其等效寫法為
Object.create(Object)
和obj.toString(obj)
抒和,省略了把obj
自身作為參數(shù)傳入到方法中的這個(gè)步驟队询,讓整個(gè)調(diào)用看起來(lái)更像是obj
自身提供的方法。
1.3 添加屬性聲明
類型的定義少不了屬性和方法的聲明构诚,上例中只進(jìn)行了方法的聲明蚌斩,這節(jié)將會(huì)重點(diǎn)講述屬性如何進(jìn)行聲明。利用上面的例子范嘱,我們?cè)俳oObject
增加一個(gè)屬性送膳。
-- 聲明屬性
Object.tag = 999;
很簡(jiǎn)單,這樣就完成了一個(gè)簡(jiǎn)單的屬性定義丑蛤。在代碼中可以這樣使用:
local obj = Object:create();
print (obj.tag); -- 輸出999
但是問題來(lái)了叠聋,在面向?qū)ο笾校鋵?shí)類型和實(shí)例應(yīng)該都會(huì)擁有屬性受裹,即類屬性和實(shí)例屬性碌补。那么如果直接在Object
中定義屬性是沒有辦法區(qū)分這是類屬性還是實(shí)例屬性的。所以棉饶,這里借鑒了javascript中的prototype
機(jī)制厦章。簡(jiǎn)單來(lái)說(shuō)就是把類型和實(shí)例定義分離,讓所有的實(shí)例屬性和實(shí)例方法定義到prototype
中照藻。類型變量中只保留類屬性和類方法袜啃。接下來(lái)開始動(dòng)手改寫Object
:
-- 定義類型
Object = {};
-- 設(shè)置__index元方法
Object.__index = Object
-- 定義類型屬性
Object.objCount = 0;
-- 定義構(gòu)造函數(shù)
function Object:create()
Object.objCount = Object.objCount + 1;
local instance = {};
setmetatable(instance, self.prototype);
return instance;
end
-- 定義類方法
function Object:outputObjectTag(object)
print (object.tag);
end
-- 定義類型的prototype
Object.prototype = {};
-- 設(shè)置prototype的__index元方法
Object.prototype.__index = Object.prototype;
-- 設(shè)置prototype的__gc元方法
Object.prototype.__gc = function (instance)
print(instance, "destroy");
end
-- 定義實(shí)例對(duì)象屬性
Object.prototype.tag = 999;
-- 定義實(shí)例對(duì)象方法
function Object.prototype:toString()
return tostring(self);
end
上面例子主要做出了如下幾點(diǎn)改動(dòng):
- 在類型
Object
中增加一個(gè)類屬性prototype
,并設(shè)置其__index
元方法指向。 -
create
方法中之前設(shè)置元表為Object
,現(xiàn)在改為Object.prototype
宰睡。 -
__gc
元方法從Object
轉(zhuǎn)移到Object.prototype
中,因?yàn)閷?shí)例構(gòu)造時(shí)綁定元表是prototype
熟妓,所以銷毀監(jiān)聽要相對(duì)應(yīng)轉(zhuǎn)移。 -
tag
屬性和toString
方法轉(zhuǎn)移到Object.prototype
中進(jìn)行定義栏尚。
通過(guò)這樣的調(diào)整起愈,整個(gè)結(jié)構(gòu)被劃分為兩部分,讓類型結(jié)構(gòu)更加清晰。使用方式是沒有變化的告材,如下面代碼所示:
local obj = Object:create();
print (obj.tag); -- 輸出999
Object:outputObjectTag(obj); -- 輸出999
print (Object.objCount); -- 輸出1
1.4 類型繼承
繼承是面向?qū)ο笾幸粋€(gè)很重要的特性坤次,要想在lua中實(shí)現(xiàn)該特性也相對(duì)比較簡(jiǎn)單古劲,配合元表和__index
元方法就可以了斥赋。下面我們新增一個(gè)Person
類型繼承于Object
:
-- 創(chuàng)建類型并綁定父類作為元表
Person = {};
Person.__index = Person;
setmetatable(Person, Object);
-- 創(chuàng)建prototype并綁定父類prototype作為元表
Person.prototype = {};
Person.prototype.__index = Person.prototype;
setmetatable(Person.prototype, Object.prototype);
通過(guò)上面的寫法即可實(shí)現(xiàn)類型的繼承,調(diào)用代碼如下:
local person = Person:create();
print (person.tag) -- 輸出999
上面代碼中沒有看到Person
類型定義create
方法产艾,但是能夠正常被調(diào)用并生成對(duì)象疤剑,這得益于Object
的create
方法綁定元表的操作使用的是self
而不是指定類型,對(duì)于其他的方法也可以嘗試使用這種技巧進(jìn)行處理闷堡。
但是如果每次創(chuàng)建一個(gè)新的類型都要寫這么一大串東西是一件繁瑣的事情隘膘。為了讓我們可以偷懶,下面對(duì)這塊內(nèi)容進(jìn)行封裝并改寫Object
:
function Object:subclass(typeName)
-- 以傳入類型名稱作為全局變量名稱創(chuàng)建table
_G[typeName] = {};
-- 設(shè)置元方法__index,并綁定父級(jí)類型作為元表
local subtype = _G[typeName];
subtype.__index = subtype;
setmetatable(subtype, self);
-- 創(chuàng)建prototype并綁定父類prototype作為元表
subtype.prototype = {};
subtype.prototype.__index = subtype.prototype;
subtype.prototype.__gc = self.prototype.__gc;
setmetatable(subtype.prototype, self.prototype);
return subtype;
end
上面代碼主要新增了subclass
方法杠览。將之前寫的一大串操作放入了這個(gè)方法弯菊,以后要?jiǎng)?chuàng)建新的子類則可以像下面這樣操作:
-- 創(chuàng)建繼承Object的Person類
Object:subclass("Person");
Person.prototype.name = "vim";
local p = Person:create();
print (p.name); -- 輸出vim
-- 創(chuàng)建繼承Person的Chinese類
Person:subclass("Chinese");
Chinese.prototype.skin = "yellow";
local ch = Chinese:create();
print (ch.name, ch.skin); -- 輸出vim yellow
1.5 方法重載
在類型繼承的同時(shí),可能會(huì)出現(xiàn)父類的某個(gè)方法需要在子類中進(jìn)行特殊化處理的情況踱阿,那么方法的重載就非常有必要了管钳。而在重載過(guò)程有可能需要調(diào)用父類方法,為了達(dá)到這種效果软舌,我們對(duì)繼承方法進(jìn)行改寫才漆,將繼承鏈搭建起來(lái),修改代碼如下:
function Object:subclass(typeName)
-- 以傳入類型名稱作為全局變量名稱創(chuàng)建table
_G[typeName] = {};
-- 設(shè)置元方法__index,并綁定父級(jí)類型作為元表
local subtype = _G[typeName];
-- 設(shè)置類型父類
subtype.super = self;
subtype.__index = subtype;
setmetatable(subtype, self);
-- 創(chuàng)建prototype并綁定父類prototype作為元表
subtype.prototype = {};
subtype.prototype.__index = subtype.prototype;
subtype.prototype.__gc = self.prototype.__gc;
setmetatable(subtype.prototype, self.prototype);
return subtype;
end
上例改寫了subclass
方法佛点,在類型中新增super
屬性醇滥,讓子類與父類進(jìn)行關(guān)聯(lián)。接下來(lái)要再給出一條規(guī)范:調(diào)用父類方法時(shí)需要使用Class.super.prototype.function(self, params)
形式超营。 為了加深理解鸳玩,我們直接上例子:
function Object.prototype:output(a, b)
-- 求和
return a + b;
end
-- 創(chuàng)建子類Child
Object:subclass("Child");
function Child.prototype:output(a, b)
-- 求和后平方
local sum = Child.super.prototype.output(self, a, b);
return sum ^ 2;
end
local c = Child:create();
print (c:output(2, 2)); -- 輸出16
上例中Object
對(duì)象定義了output
方法,用來(lái)輸出兩個(gè)參數(shù)的總和演闭。而在子類Child
中重載了該方法怀喉,先調(diào)用父類方法求和,然后對(duì)結(jié)果求平方并返回船响。
調(diào)用父類的方式顯得有點(diǎn)臃腫和不簡(jiǎn)潔躬拢,但這是我目前唯一能夠想到的方法,如果有更好的方式歡迎大家提出來(lái)給我建議见间。
1.6 優(yōu)化工作
通過(guò)上面的設(shè)計(jì)聊闯,在lua中面向?qū)ο窬幊袒旧夏軌驖M足需要,在這小節(jié)中主要是針對(duì)設(shè)計(jì)中一些操作進(jìn)行簡(jiǎn)化米诉。
1.6.1 類型的字符串描述轉(zhuǎn)換
之前菱蔬,我們定義了一個(gè)toString
的實(shí)例方法來(lái)讓對(duì)象進(jìn)行字符串的轉(zhuǎn)換。其實(shí)__tostring
元方法可以實(shí)現(xiàn)這樣的功能,并且能夠很好地結(jié)合print
和tostring
系統(tǒng)方法拴泌。下面我們把toString
方法替換掉:
function Object:create()
local instance = {};
instance.class = self;
setmetatable(instance, self.prototype);
return instance;
end
function Object:subclass(typeName)
-- 以傳入類型名稱作為全局變量名稱創(chuàng)建table
_G[typeName] = {};
-- 設(shè)置元方法__index,并綁定父級(jí)類型作為元表
local subtype = _G[typeName];
subtype.name = typeName;
subtype.super = self;
subtype.__index = subtype;
setmetatable(subtype, self);
-- 創(chuàng)建prototype并綁定父類prototype作為元表
subtype.prototype = {};
subtype.prototype.__index = subtype.prototype;
subtype.prototype.__gc = self.prototype.__gc;
subtype.prototype.__tostring = self.prototype.__tostring;
setmetatable(subtype.prototype, self.prototype);
return subtype;
end
Object.prototype.__tostring = function (instance)
return "[" .. instance.class.name .." object]";
end
代碼中主要調(diào)整內(nèi)容為:
-
create
方法中在創(chuàng)建實(shí)例時(shí)將類型賦予實(shí)例的屬性class
魏身。主要是為了方便演示__tostring
的輸出。 -
subclass
方法中需要對(duì)子類prototype
的__tostring
元方法進(jìn)行賦值蚪腐,讓其與父類處理相同(注:__gc
箭昵、__tostring
跟__index
有點(diǎn)不一樣,不會(huì)遞歸需要元表方法回季,作用只在本級(jí)元表有效)家制。 - 移除
toString
方法,并增加__tostring
元方法泡一。
下面例子演示其輸出:
local obj = Object:create();
print(obj); -- 輸出[Object object];
Object:subclass("Child");
local c = Child:create();
print (c); -- 輸出[Child object];
1.6.2 簡(jiǎn)化構(gòu)造函數(shù)
目前我們所定義的構(gòu)造函數(shù)create
其實(shí)是類型的一個(gè)方法颤殴,雖然有規(guī)范來(lái)約束編碼人的行為,但是也有可能存在構(gòu)造函數(shù)被覆蓋的情況鼻忠。那么最好的辦法就是讓我們的構(gòu)造函數(shù)整合到lua語(yǔ)法中涵但,剛好lua提供的__call
元方法就能夠做到這一點(diǎn)。它能夠使用括號(hào)語(yǔ)法來(lái)讓類型進(jìn)行實(shí)例構(gòu)建帖蔓,如:local instance = Object()
矮瘟。下面我們直接貼出實(shí)現(xiàn)代碼:
-- 對(duì)象構(gòu)造器
local ObjectConstructor = {};
ObjectConstructor.__call = function (type)
local instance = {};
instance.class = type;
setmetatable(instance, type.prototype);
return instance;
end
Object = {};
Object.__call = ObjectConstructor.__call;
setmetatable(Object, ObjectConstructor);
function Object:subclass(typeName)
-- 以傳入類型名稱作為全局變量名稱創(chuàng)建table
_G[typeName] = {};
-- 設(shè)置元方法__index,并綁定父級(jí)類型作為元表
local subtype = _G[typeName];
subtype.name = typeName;
subtype.super = self;
subtype.__call = ObjectConstructor.__call;
subtype.__index = subtype;
setmetatable(subtype, self);
-- 創(chuàng)建prototype并綁定父類prototype作為元表
subtype.prototype = {};
subtype.prototype.__index = subtype.prototype;
subtype.prototype.__gc = self.prototype.__gc;
subtype.prototype.__tostring = self.prototype.__tostring;
setmetatable(subtype.prototype, self.prototype);
return subtype;
end
-- 省略O(shè)bject其他定義實(shí)現(xiàn)
上述代碼中創(chuàng)建了一個(gè)ObjectConstructor
的變量,主要實(shí)現(xiàn)了__call
元方法讨阻,而元方法中的實(shí)現(xiàn)就是我們之前的create
方法實(shí)現(xiàn)芥永。
為什么需要多出一個(gè)ObjectConstructor
?主要是因?yàn)樵椒ㄖ粚?duì)綁定其的變量有效钝吮,所以如果你直接在Object
中實(shí)現(xiàn)__call
元方法埋涧,然后調(diào)用Object()
其實(shí)是不起作用的,因?yàn)樗陨碜鳛樽兞康臅r(shí)候就不是元表奇瘦。因此才需要有一個(gè)ObjectConstructor
作為Object
的元表棘催。
我們也看到Object._call = ObjectConstructor.__call
和subtype.__call = ObjectConstructor.__call
,這里表示類型還是要定義__call
元方法的耳标,目的是為了被子類化時(shí)醇坝,子類也要能夠正常調(diào)用構(gòu)造函數(shù)。
通過(guò)這樣的調(diào)整次坡,構(gòu)造就變得很簡(jiǎn)潔了呼猪,也不怕存在構(gòu)造函數(shù)覆蓋問題,如:
local obj = Object();
print (obj); -- 輸出[Object object];
Object:subclass("Child");
local c = Child();
print (c); -- 輸出[Child object];
上面所說(shuō)的就是使用元表來(lái)實(shí)現(xiàn)的面向?qū)ο蟮娜績(jī)?nèi)容砸琅,接下來(lái)要講的就是使用LuaScriptCore(簡(jiǎn)稱LSC)這個(gè)第三方框架是如何實(shí)現(xiàn)面向?qū)ο缶幊獭?/p>
2. LuaScriptCore方式
LSC是鄙人開發(fā)的一套用于簡(jiǎn)化iOS宋距、OSX、Android症脂、Unity3D平臺(tái)與lua橋接的框架谚赎。它能夠很方便地將原生定義的類型導(dǎo)出到lua層中使用淫僻,同時(shí)也涵蓋了上面使用元表實(shí)現(xiàn)的所有面向?qū)ο蠊δ堋8信d趣的同學(xué)可以到這里了解和下載壶唤,接下來(lái)我們一起看看怎么樣使用LSC來(lái)面向?qū)ο缶幊獭?/p>
LSC的集成雳灵,這里就不在詳細(xì)描述了,可以根據(jù)自己集成的平臺(tái)查看相關(guān)的文檔(iOS & OSX闸盔、Android悯辙、Unity3D)。
2.1 Object類型
LSC中默認(rèn)聲明Object
類型蕾殴,該類型包含下面方法和屬性:
名稱 | 說(shuō)明 |
---|---|
Object.name |
類型的名稱笑撞,每個(gè)類型都包含這個(gè)屬性 |
Object.prototype |
類型原型岛啸,用于定義類型實(shí)例的屬性和方法 |
Object.super |
類型的父類钓觉,Object 沒有父類,為nil
|
Object:subclass(typeName) |
子類化方法坚踩,向該方法傳入類型名稱則可以構(gòu)建對(duì)應(yīng)名稱的類型荡灾,如:Object:subclass('Child')
|
Object:subclassOf(type) |
用于檢測(cè)指定類型是否為該類型的父類,如:Child:subclassOf(Object)
|
Object:typeMapping(platform, nativeTypeName, alias) |
將原生類型映射到alias 指定的別名中瞬铸,往后可以根據(jù)別名來(lái)方面該類型批幌。如:Object:typeMapping('ios', 'LSCTestType', 'Test')
|
Object.prototype.super |
類型原型的父級(jí)原型,Object 沒有父級(jí)原型嗓节,為nil
|
Object.prototype:instanceOf(type) |
判斷是否為該類型或其子類型實(shí)例荧缘。如:local c = Child(); obj:instanceOf(Object);
|
如果需要構(gòu)造一個(gè)Object
對(duì)象,可以如下操作:
local obj = Object();
如果需要監(jiān)聽類型的構(gòu)造和銷毀拦宣,可以在prototype
中定義init
和destroy
方法截粗,如:
function Object.prototype:init()
print ("對(duì)象被構(gòu)造...");
end
function Object.prototype:destroy()
print ("對(duì)象被銷毀...");
end
local obj = Object();
obj = nil;
執(zhí)行后打印以下內(nèi)容:
對(duì)象被構(gòu)造...
對(duì)象被銷毀...
2.2 子類化
通過(guò)Object.subclass
可以進(jìn)行類型子類化,如:
Object:subclass('Person');
Person:subclass('Chinese');
子類化后可以為類型定義方法和屬性鸵隧,如:
Person.prototype.age = 0;
Person.prototype.name = {
get = function (self)
return self._name;
end
set = function (self, value)
self._name = value;
end
};
function Person.prototype:speak()
print ("xxxxxxxxx");
end
function Chinese.prototype:speak()
print ("我說(shuō)的是中文....");
end
上面代碼需要注意的地方是name
屬性的定義绸罗,LSC支持為屬性定義getter
和setter
。具體的格式要求就如上面豆瘫,需要傳入一個(gè)table
變量珊蟀,變量中帶有get
和set
兩個(gè)key,并且兩個(gè)key的value都是一個(gè)function
外驱。
2.3 方法重載
LSC中方法重載在上例中已經(jīng)演示(Person
的speak
方法在Chinese
中重寫)育灸。其形式與元表方式相同,如果需要調(diào)用父級(jí)方法昵宇,需要通過(guò)Class.prototype.function(self, params)
形式進(jìn)行磅崭。
LSC其實(shí)是對(duì)元表方式的一種封裝,其中大部分約定和實(shí)現(xiàn)方式都與上面所說(shuō)的基本一致趟薄。目的就是讓開發(fā)者不用過(guò)多關(guān)注里面的實(shí)現(xiàn)绽诚,像一般的高級(jí)語(yǔ)言一樣可以進(jìn)行面向?qū)ο蟮木幊獭?/p>
到這里所有內(nèi)容都已經(jīng)講述完畢,如果有疑問和建議,歡迎留言和提問~