上一篇记录了我使用 Slua.Class 来实现面向对象扩展 C# 中得类,但实际使用中,更多地情况是直接在 lua 中定义基类然后扩展,于是触发了我重新思考下是否两种形式应该统一用一种,目前的方案中,有一个不好的地方是,每一个派生类的实例,其实内部会有多个实例(每一个继承的类都有个对应的实例,参考 __call 的调用),所以继承层次越深,内部的实例越多,而这些父类的实例仅仅是提供了属性和方法而已,没有其它作用,这其实造成了一种浪费,但如果改动的话,我想整个结构和基础都得该,影响了本身 slua 中代码的兼容性。
我仔细阅读了云风给出的 lua oop 方案,方法够精简,确实也解决了我想解决的问题,所有的类对象,都只有一个实例,他们查询父类的方法和属性,都通过缓存的 table 来查询,避免了浪费。但对于我个人目前的需求来讲,还有些不足:
- 包装的过于严实,无法直接使用 类名.静态方法名 来使用静态方法;
- 无法直接使用 super 关键字来访问父类方法,这样只能强制你完全重写继承的方法;(而关于我修改的 slua 中的 通过 __base 访问父类的机制,其实有缺陷,因为 只能通过 self.__base.Method(self, ...),但是 super 应该隶属于类而不是对象,应该 NewCls.__base.Method(self, ...) 这样才对。),修改完应该每个派生类会多一个实例用来指向 super 的父类访问,而这个类是共享的,所以开销可以忽略不计;
- 为了整体代码风格统一(提供同 Slua.Class 继承类同样的实例化类方法),我需要也添加一个默认实例化方法: local obj = NewCls(...),等同于 local obj = NewCls.new(...)。
修改完的代码如下(请忽略我修改了变量名):
-- The hold all class type. local __TxClassTypeList = {} -- The inherit class function. local function TxClass(SuperType) -- Create new class type. local ClassType = {} ClassType.Ctor = false ClassType.SuperType = SuperType -- Create new class instance function. local function ClassTypeInstance(...) local Obj = {} do local Create Create = function (c, ...) if c.SuperType then Create(c.SuperType, ...) end if c.Ctor then c.Ctor(Obj, ...) end end Create(ClassType, ...) end setmetatable(Obj, {__index = __TxClassTypeList[ClassType]}) return Obj end -- The new function of this class. ClassType.new = ClassTypeInstance -- The super class type of this class. if SuperType then ClassType.super = setmetatable({}, { __index = function (t, k) local Func = __TxClassTypeList[SuperType][k] if "function" == type(Func) then t[k] = Func return Func else error("Accessing super class field are not allowed!") end end }) end -- Virtual table local Vtbl = {} __TxClassTypeList[ClassType] = Vtbl -- Set index and new index of ClassType, and provide a default create method. setmetatable(ClassType, { __index = function (t, k) return Vtbl[k] end, __newindex = function (t, k, v) Vtbl[k] = v end, __call = function (self, ...) return ClassTypeInstance(...) end }) -- To copy super class things that this class not have. if SuperType then setmetatable(Vtbl, { __index = function (t, k) local Ret = __TxClassTypeList[SuperType][k] Vtbl[k] = Ret return Ret end }) end return ClassType end
现在我可以如下使用:
-- Base class. local BaseFoo = TxClass() BaseFoo.Name = "I am BaseFoo!" function BaseFoo:Ctor() print("BaseFoo in constructor.") end function BaseFoo.PrintHello() print("Hello BaseFoo!") end function BaseFoo:Foo() print("Name is: " .. self.Name) end -- Derived class. local MyFoo = TxClass(BaseFoo) MyFoo.Age = 18 function MyFoo:Ctor() print("MyFoo in constructor.") end function MyFoo:Foo() MyFoo.super.Foo(self) print("Age is: " .. tostring(self.Age)) end -- Create instance. local bf = BaseFoo.new() bf:Foo() local mf = MyFoo() mf:Foo() BaseFoo.PrintHello() MyFoo.PrintHello()
接下来如云风所说,我应该思考下如何实现 Destructor。