Luaはオブジェクト指向プログラミングをサポートしている
現在使用しているオブジェクト指向プログラミングの実装方法をまとめておく
#メタテーブルを使用しない場合
###クラスの実装とインスタンス化
Class = {}
function Class.new()
local obj = {}
obj.func = function(self)
--関数の処理
end;
return obj
end
local instance = Class.new()
instance:func()
メタテーブルを使用しない場合はnewによって返すテーブルの中に関数を入れてあげます。
継承とオーバーライドは以下の通りです。
###継承・オーバーライド
Child = {}
function Child.new()
local obj = Class.new()
obj.func = function(self) --オーバーライド
--関数の処理
end;
return obj
end
returnするテーブルには親クラスのインスタンスを入れてあげます。
この実装の問題点は新たにインスタンスを作成するたびにメソッドを初期化する必要がある点です。
#メタテーブルを使用する場合
###instance関数
function instance(class, super, ...)
local self = (super and super.new(...) or {})
setmetatable(self, {__index = class})
setmetatable(class, {__index = super})
return self
end
子クラスの __index に親クラスを、インスタンスの __index に子クラスを設定してあげます。
これによりインスタンス(self)に存在しないキーにアクセスした時、クラスとその親クラスから探してくることができます。
__indexやmetatableについて詳しく知りたい方は、こちらを参考にしてください
###クラスの実装
Class = {
new = function(val1,val2)
local obj = instance(Class)
--ここでメンバ変数を宣言
obj.m_val1 = val1
obj.m_val2 = val2
return obj
end;
func = function(self)
-- 処理
end;
}
クラスの宣言、実装は上記のように行います。
local temp = Class.new(1,2)
temp:func()
new関数を呼んであげればinstance関数によって作成されたインスタンスを返してくれます。
このインスタンスには__indexにクラスとその親クラスが設定してあるため、実装したクラスの関数を呼び出すことができます。
ちなみに
temp.func(temp)
temp:func()
は共に自分自身をメソッドに渡す処理です。下の書き方は上の書き方の省略形ですね。
###継承
--親クラス
Parent = {
new = function(val1,val2)
local obj = instance(Parent)
--ここでメンバ変数を実装
obj.m_val1 = val1
obj.m_val2 = val2
return obj
end;
parentFunc = function(self)
-- 処理
end;
}
--子クラス
Child = {
new = function(val1,val2)
local obj = instance(Child,Parent,val1,val2)
--ここでメンバ変数を実装
return obj
end;
func = function(self)
Parent.parentFunc(self) --親クラスのメンバ関数を呼ぶ
end;
}
継承は上記のように行います。instance関数の引数に親クラスを与えてあげればよいです。
子クラス内で親クラスの関数を呼びたいときは親クラス.関数名()
でアクセスしてください。
###オーバーライド
--親クラス
Parent = {
new = function(val1,val2)
local obj = instance(Parent)
--ここでメンバ変数を実装
obj.m_val1 = val1
obj.m_val2 = val2
return obj
end;
func = function(self)
-- 処理
end;
}
--子クラス
Child = {
new = function(val1,val2)
local obj = Parent.new(Child,Parent,val1,val2)
return obj
end;
--オーバーライド
func = function(self)
-- 新しい処理
end;
}
オーバーライドをしたい時は子クラスに親クラスの関数を新たに定義します。
#速度について
kengonakajimaさんのLua OOPの速度比較によると
**metatableを使用する実装では、metatbleを使用しない実装に比べ大幅に速度が落ちるそうです。
追記
まつもとゆきひろ コードの未来では別の実装例が紹介されています。
参考
http://invalid-log.blogspot.com/2015/05/lua.html
https://github.com/kengonakajima/blog/blob/master/articles/luaoo.md