LUAオブジェクト向けプログラミング(四)多重継承
7124 ワード
Luaで多重継承を実現するには,多様なスキームがあり,pilではlua著者らが多様な継承を実現するスキームを提供しているが,個人的には,このスキームは簡潔であるが優雅ではないと考えている.その後、雲風(江湖伝説の弊害のある人)はもう一つの簡潔で優雅な解決策を提供し、その実現案はooの思想を深く把握した.しかし、風雲の実現は多重継承の場合は考慮されておらず、ここでは、風雲の実現案に基づいて拡張され、多様な継承の場合をサポートしている.
まず風雲の実現を見てみましょう.
local _class={}
function class(super)
local class_type={}
class_type.ctor=false
class_type.super=super
class_type.new=function(...)
local obj={}
do
local create
create = function(c,...)
if c.super then
create(c.super,...)
end
if c.ctor then
c.ctor(obj,...)
end
end
create(class_type,...)
end
setmetatable(obj,{ __index=_class[class_type] })
return obj
end
local vtbl={}
_class[class_type]=vtbl
setmetatable(class_type,{__newindex=
function(t,k,v)
vtbl[k]=v
end
})
if super then
setmetatable(vtbl,{__index=
function(t,k)
local ret=_class[super][k]
vtbl[k]=ret
return ret
end
})
end
return class_type
end
上記の関数classを使用すると、luaでクラスを簡単に定義できます.
base_type=class() -- base_type function base_type:ctor(x) -- base_type print("base_type ctor") self.x=x end function base_type:print_x() -- base_type:print_x print(self.x) end function base_type:hello() -- base_type:hello print("hello base_type") end
次の方法で、単一の継承を実現できます.
child=class(base_type)--クラスchildがbase_に継承されることを定義します.type
function child:ctor() -- child print("child ctor") end function child:hello() -- base_type:hello child:hello print("hello child") end
childクラスのインスタンスを作成します.
obj = child.new(1) -- ,base_type ctor child ctor 。 。 obj:print_x() -- 1 , base_type 。 obj:hello() -- hello child , 。
多層単一継承を実現するには、クラスchild 2を作成し続け、childに継承することで、3層単一継承を実現することができます.ここでclass関数は1パラメータ以下の場合のみ受信し,上のclass関数で多重継承を実現しようとすると実現できないが,それに基づいて修正して実現できる.
主な変更点は次のとおりです.
>classのパラメータを可変パラメータに変更すると、任意のパラメータを受信できます.
>子クラスのすべての親を再帰的に巡回し、対応するアクションを実行する必要があります.
変更後のclassコードは次のとおりです.
local _class={} function class(...) local cls = {}
cls.ctor=false--コンストラクション関数cls._が存在するかどうかbase = {...}--現在のクラスのベースクラスは、1つ、複数、clsがない可能性があります.new = function(...) local obj = {} do local create create = function(c,...) if c.__base then for _, k in pairs(c.__base) do create(k, ...) end
end if c.ctor then c.ctor(obj, ...) end end create(cls,...) end
setmetatable(obj, { __index=_class[cls] }) return obj end
local vtbl={} _class[cls]=vtbl setmetatable(cls, {__newindex= function(t, k, v) vtbl[k] = v
end }) if cls.__base then setmetatable(vtbl, {__index = function(tab, key) for _, base_cls in pairs(cls.__base) do local ret = _class[base_cls][key] if ret then vtbl[key] = ret return ret end end return nil end }) end return cls end
次に検証します.まず、ベースクラスNameとAccountを2つ作成します.
Name = class()
function Name:ctor() print("Name ctor") self.name = "Smith" end
function Name:getName() print("Your name: ".. self.name) end
Account = class()
function Account:ctor() print("Account ctor") self.balce = 1000 end
function Account:deposit(v) self.balce = self.balce + v end
function Account:getBalance() print(self.balce) end
function Account:withdraw(v) if self.balce < v then print(string.format("your account remains %d, not enough %d", self.balce, v)) return end self.balce = self.balce - v end
次に、サブクラスSpecialAccountを作成し、上の2つのベースクラスを継承します.
SpecialAccount = class(Name, Account) function SpecialAccount:ctor() print("SpecialAccount ctor") end
SpecialAccountクラスのインスタンスを作成し、継承されたベースクラスの関連インタフェースを呼び出します.
sc = SpecialAccount.new()
sc:getName() sc:getBalance()
出力結果:
Name ctor
Account ctor
SpecialAccount ctor
Your name: Smith
1000
SpecialAccountのオブジェクトが正しく構築され、親のメソッドが継承されていることを示します.しかし、上記の実装には、サブクラスの関数で親クラスの同名関数を呼び出すことができないなど、わずかな欠陥が残っており、mywcyflは解決策を示しており、参考にすることができる.もう1つの問題は、多層継承で、サブクラスのnewメソッドにパラメータを渡すと、親クラスのパラメータの初期化にも使用され、それが合理的かどうか分かりません.
(全文完了)