標準のメタテーブル メソッドの代わりに、関数型の方法で lua でオブジェクト指向プログラミングを行う方法を発見 (および作成) しました。はるかに多くの機能を備えています (しゃれは意図していません) が、パフォーマンスが低下する可能性があるのではないかと心配しています。私の目標は、lua で記述されたサーバーで実験することであり、この OOP ソリューションを使用したいと考えていました。とにかく、ここに新しいオブジェクトとサブクラスを作成するための関数を保持する私のclass.luaがあります。
local classes = setmetatable({}, {__mode = "k"}) -- Allow the GC to empty this as needed.
function class(f, super)
classes[f] = {super = super}
end
function new(f, obj, ...)
local fenv = getfenv(f)
if type(obj) ~= "table" then
error("bad argument: expected table, got " .. type(obj) , 2)
end
if classes[f] and classes[f].super then
new(classes[f].super, obj, ...)
local super = obj
obj = setmetatable({}, { __index = super })
obj.super = super
else
setmetatable(obj,{__index = fenv})
end
obj.this = obj
setfenv(f, obj)
f()
setfenv(f, fenv)
if obj.init then
obj.init( ... )
end
return obj
end
使い方はかなり簡単です。次の例を見てください。
function Person()
local privateVar = math.random()
age, name, gender = nil, nil, nil
function init(age, name, gender)
this.age = age
this.name = name
this.gender = gender
end
function getAge()
return age
end
function getName()
return name
end
function getGender()
return gender
end
function getPrivateVar()
return privateVar
end
end
そして、オブジェクトを作成するには
obj = new(Person, {}, "John", 30, "male")
サブクラス化も簡単
function Female()
function init(name, age)
super.init(name, age, "female")
end
end
class(Female, Person)
サブクラス化したい場合は、関数を呼び出して何かをクラスにするだけでよいことに注意してください。
new を呼び出すときは、クラス、オブジェクト、および引数を渡します。オブジェクトのメタテーブルは、クラスの元の環境のインデックスを持つように設定されています。次に、スーパーが決定され、作成されます。次に、クラス関数が実行されて、すべてのインスタンス値が作成されます。次に、init が呼び出されます。
メタテーブルに対するこれの利点の 1 つは、他のコードがクラスを変更できず、そのクラスの既存および今後存在するすべてのインスタンスを変更できないことです。現在、そのようなことを行う唯一の方法は、クラスへのすべての参照がハッカーのダミー クラスを参照していることを確認するために、環境をスウィズルしてハックすることです。
その上、プライベート変数をサポートしています。クラス関数でローカルに宣言するだけで、準備完了です。
しかし、インスタンス化ごとにすべてのインスタンス メソッドを 1 回作成するという事実が、パフォーマンスの問題を引き起こすのではないかと考えています。これはメモリを食べますか?ここで何が問題になる可能性がありますか?
また、問題があります。これは多重継承をサポートしていますが、スーパー メソッドを呼び出し、スーパーがメソッドを呼び出すと、インスタンス化されたクラスではなく、スーパー クラスのメソッドが呼び出されます。インスタンス化されたクラスから呼び出す方法はありますか?