繼承教學 |
|
以下範例執行沒有繼承的類別
SimpleClass = {} SimpleClass_mt = { __index = SimpleClass } -- This function creates a new instance of SimpleClass -- function SimpleClass:create() local new_inst = {} -- the new instance setmetatable( new_inst, SimpleClass_mt ) -- all instances share the same metatable return new_inst end -- Here are some functions (methods) for SimpleClass: function SimpleClass:className() print( "SimpleClass" ) end function SimpleClass:doSomething() print( "Doing something" ) end
在以上範例中,SimpleClass
代表一個包含所有類別方法的表格,例如類別宣告。SimpleClass_mt
是我們會附加到所建立各類別執行個體的元表格。函式 SimpleClass:create()
會建立一個類別 SimpleClass
的執行個體。建造類別執行個體牽涉到建立一個空白表格,接著將我們的 SimpleClass
元方法附加到它。附加元方法的結果是新的執行個體會尋找我們所附加的元表格,以取得它的客製化行為。
對執行個體的方法呼叫會觸發執行個體上的「索引」事件,導致在執行個體元表格的「__index
」成員上進行查找。__index
成員只是一個指向 SimpleClass
的參考。因此,對執行個體的方法呼叫將導致在 SimpleClass
表格中執行查找。
以下是範例
> simple = SimpleClass:create() > > simple:className() SimpleClass > > simple:doSomething() Doing something
現在我們要建立新的類別 SubClass
,它會繼承函式,並可從 SimpleClass
覆寫(選擇性)。
-- Create a new class that inherits from a base class -- function inheritsFrom( baseClass ) -- The following lines are equivalent to the SimpleClass example: -- Create the table and metatable representing the class. local new_class = {} local class_mt = { __index = new_class } -- Note that this function uses class_mt as an upvalue, so every instance -- of the class will share the same metatable. -- function new_class:create() local newinst = {} setmetatable( newinst, class_mt ) return newinst end -- The following is the key to implementing inheritance: -- The __index member of the new class's metatable references the -- base class. This implies that all methods of the base class will -- be exposed to the sub-class, and that the sub-class can override -- any of these methods. -- if baseClass then setmetatable( new_class, { __index = baseClass } ) end return new_class end
函式 inheritsFrom(baseClass)
採用單一參數,即我們想繼承的類別宣告。函式會傳回一個類別宣告,我們接著可以調整。new_class
是新的類別宣告,待傳回。巢狀函式 new_class:create()
是傳回的類別宣告一部分,且會建立我們正在建立的子類別新執行個體。此函式會建立一個 newinst
表格,且會使用我們的類別表格包含它的方法。新的類別表格接著會在 baseClass
中尋找,如果找不到我們需要的方法,我們就會繼承它的方法。
建構於 SimpleClass
,我們現在建立稱為 SubClass
,且會從 SimpleClass
繼承並覆寫 className()
的類別
> -- Create a new class that inherits from SimpleClass > SubClass = inheritsFrom( SimpleClass ) > > -- override className() function > function SubClass:className() print( "SubClass" ) end > > -- Create an instance of SimpleClass > simple = SimpleClass:create() > > simple:className() SimpleClass > > simple:doSomething() Doing something > > -- Create an instance of SubClass > sub = SubClass:create() > > sub:className() -- Call overridden method SubClass > > sub:doSomething() -- Call base class method Doing something >
我們現在可以擴充我們的繼承結構,並新增其他語言中常見的功能,例如存取類別的超級類別,以及提供類型 ID 功能的 isa()
方法
-- A new inheritsFrom() function -- function inheritsFrom( baseClass ) local new_class = {} local class_mt = { __index = new_class } function new_class:create() local newinst = {} setmetatable( newinst, class_mt ) return newinst end if nil ~= baseClass then setmetatable( new_class, { __index = baseClass } ) end -- Implementation of additional OO properties starts here -- -- Return the class object of the instance function new_class:class() return new_class end -- Return the super class object of the instance function new_class:superClass() return baseClass end -- Return true if the caller is an instance of theClass function new_class:isa( theClass ) local b_isa = false local cur_class = new_class while ( nil ~= cur_class ) and ( false == b_isa ) do if cur_class == theClass then b_isa = true else cur_class = cur_class:superClass() end end return b_isa end return new_class end
使用範例
> SimpleClass = inheritsFrom( nil ) -- pass nil because SimpleClass has no super class > > SubClass = inheritsFrom( SimpleClass ) > > FinalClass = inheritsFrom( SubClass ) > > sub = SubClass:create() > fc = FinalClass:create() > > print( fc:isa( SubClass ) ) true > print( fc:isa( FinalClass ) ) true > print( sub:isa( SubClass ) ) true > print( sub:isa( FinalClass ) ) false
大部分的程式碼基本上與上述相同,但已精簡至只有讓「原型基礎程式設計」運作所需的精華。更精確地說,它允許使用複製與原型委派進行原型程式設計。存取物件中未設定的屬性會委派給其原型。此程式碼使用 table
表格作為最基本的原型,而 object
則作為 table
的專門化。函式 object.isa
對原型典範來說並非絕對必要,但更便利。
clone(base_object[, clone_object]) -> table
參數
base_object
:要複製的基本物件表格。clone_object
:可選物件表格,用於轉換成 base_object
的複製。傳回
table
:新的複製。如果 new_object
不是 table
類型,則會傳回 new_object
(如果不是 nil
),否則傳回 base_object
。new_object
的元表格設定為本身,而其 __index
現在指向其原型 base_object
。clone
也可用作 object.clone
。
isa( clone_object, base_object) -> bool
參數
clone_object
:要檢查的複製表格base_object
:clone_object
預期中的基礎表格。傳回
bool
:複製在原型階層中具有基礎。如果任一引數都不是 table
,isa
會改為傳回類型的比較。它也可用作 object.isa
。
function clone( base_object, clone_object ) if type( base_object ) ~= "table" then return clone_object or base_object end clone_object = clone_object or {} clone_object.__index = base_object return setmetatable(clone_object, clone_object) end function isa( clone_object, base_object ) local clone_object_type = type(clone_object) local base_object_type = type(base_object) if clone_object_type ~= "table" and base_object_type ~= table then return clone_object_type == base_object_type end local index = clone_object.__index local _isa = index == base_object while not _isa and index ~= nil do index = index.__index _isa = index == base_object end return _isa end object = clone( table, { clone = clone, isa = isa } )
-- testing "isa" foo = object:clone() bar = object:clone() baz = foo:clone() print( foo:isa(object) ) print( bar:isa(foo) ) print( baz:isa(foo) ) --[[ output: true false true ]] --testing prototype delegation foo = object:clone() bar = foo:clone() function foo:speak() print(self.thoughts or "foo has no thoughts") end bar:speak() --[[ output: foo has no thoughts ]] bar.thoughts = "I may be a clone, but I'm an individual!" bar:speak() --[[ output: I may be a clone, but I'm an individual! ]]