Lua面向?qū)ο缶幊?/h1>

在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è)步驟:

  1. 先創(chuàng)建一個(gè)作為元表的table
  2. 設(shè)置需要實(shí)現(xiàn)的元方法惰赋。
  3. 使用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)鍵,并且效果很好)损拢。具體找尋方式如下圖所示:

__index處理流程示意圖

元方法__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ì)象疤剑,這得益于Objectcreate方法綁定元表的操作使用的是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é)合printtostring系統(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.__callsubtype.__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中定義initdestroy方法截粗,如:

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支持為屬性定義gettersetter。具體的格式要求就如上面豆瘫,需要傳入一個(gè)table變量珊蟀,變量中帶有getset兩個(gè)key,并且兩個(gè)key的value都是一個(gè)function外驱。

2.3 方法重載

LSC中方法重載在上例中已經(jīng)演示(Personspeak方法在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)講述完畢,如果有疑問和建議,歡迎留言和提問~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

  • 序言:七十年代末恩够,一起剝皮案震驚了整個(gè)濱河市卒落,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜂桶,老刑警劉巖儡毕,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扑媚,居然都是意外死亡腰湾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門疆股,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)费坊,“玉大人,你說(shuō)我怎么就攤上這事旬痹「骄” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵两残,是天一觀的道長(zhǎng)永毅。 經(jīng)常有香客問我,道長(zhǎng)人弓,這世上最難降的妖魔是什么沼死? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮崔赌,結(jié)果婚禮上意蛀,老公的妹妹穿的比我還像新娘。我一直安慰自己峰鄙,他們只是感情好浸间,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吟榴,像睡著了一般魁蒜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吩翻,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天兜看,我揣著相機(jī)與錄音,去河邊找鬼狭瞎。 笑死细移,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的熊锭。 我是一名探鬼主播弧轧,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼雪侥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了精绎?” 一聲冷哼從身側(cè)響起速缨,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎代乃,沒想到半個(gè)月后旬牲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搁吓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年原茅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堕仔。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡擂橘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贮预,到底是詐尸還是另有隱情贝室,我是刑警寧澤契讲,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布仿吞,位于F島的核電站,受9級(jí)特大地震影響捡偏,放射性物質(zhì)發(fā)生泄漏唤冈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一银伟、第九天 我趴在偏房一處隱蔽的房頂上張望你虹。 院中可真熱鬧,春花似錦彤避、人聲如沸傅物。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)董饰。三九已至,卻和暖如春圆米,著一層夾襖步出監(jiān)牢的瞬間卒暂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工娄帖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留也祠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓近速,卻偏偏與公主長(zhǎng)得像诈嘿,于是被迫代替她去往敵國(guó)和親堪旧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容