-- middleclass.lua - v2.0 (2011-09)
--记录所有由这个体系建立的表,用来记录创建的所有类表
local _classes = setmetatable({}, {__mode = "k"})
--类元表字典 klass为传入的表 即代表一个类 用来给这个klass类表的static表建立访问关系,关系如下注释
local function _setClassDictionariesMetatables(klass)
local dict = klass.__instanceDict
dict.__index = dict
local super = klass.super
if super then
--有父类表时
--得到父类表的static
--先把当前klass表的__instanceDict表的元表设为klass的父类表的__instanceDict表(由上知道__instanceDict表有__index字段, 又指向其自身)
--意为:访问当前表的__instanceDict表时找不到,就到父类表的__instanceDict表中去找
--同样把当前klass表的static表设置一个元表,该元表的__index方法如下
--意为:访问当前klass表的static表时,如果直接找不到,会优先到其__instanceDict表去找(由上,也找不到到其父类的__instanceDict表总找)
--再找不到,到其父类的static表里找
local superStatic = super.static
setmetatable(dict, super.__instanceDict)
setmetatable(klass.static, { __index = function(_,k) return dict[k] or superStatic[k] end })
else
--没有父类表时
--给这个klass表的内部的static表设置一个元表
--元表的__index字段为一个函数(table, key), table为哑元,所以这个函数接受了那个key
--函数从这个klass表的内部的__instanceDict表中获取,而__instanceDict表的__index字段又指向其自身
--(注意:并不是其元表的index,也就是仅仅是为了能把__instanceDict也能作为一个接受值得元表用)
--综上:也就是访问这个klass的static表时,如果没有就到其__instanceDict表中去找
setmetatable(klass.static, { __index = function(_,k) return dict[k] end })
end
end
--klass为一个表 给这个klass创建元表,即给其建立访问关系
local function _setClassMetatable(klass)
--[[
设__tosring函数,为class..name 方便打印
设__index为其自身的static表,即访问自己没有就找自己的static表
设__newindex为自己的__instanceDict,即赋值新元素值时,给自己的__instanceDict赋值而不是给自己
设__call,表示以函数形式调用这个表时的操作 即:实际是调用自己的new,模仿了构造函数的形式
--]]
setmetatable(klass, {
__tostring = function() return "class " .. klass.name end,
__index = klass.static,
__newindex = klass.__instanceDict,
__call = function(self, ...) return self:new(...) end
})
end
--name新建类表的类名 super父类表
local function _createClass(name, super)
--构造表 等价于["name"] = name
local klass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} }
klass.subclasses = setmetatable({}, {__mode = "k"}) --设置klass的subclasses表的元表
_setClassDictionariesMetatables(klass)--设置自己的static表的访问关系
_setClassMetatable(klass)--设置自己的访问关系
_classes[klass] = true--以这个类表作为键,在__Classes里设为true,应该时用来记录所有的创建的类表,同时增加一个引用,使其不会被回收
return klass
end
--传入表和元方法名字字符串 返回一个函数 注意返回的时一个函数 而不是函数的值
local function _createLookupMetamethod(klass, name)
return function(...)
--的到其父类的元方法,然后调用并把值传递出去
local method = klass.super[name]
assert( type(method)=='function', tostring(klass) .. " doesn't implement metamethod '" .. name .. "'" )
return method(...)
end
end
--给klass建立元方法 注意:调用这个函数时已经建立访问关系,所有元方法时建立在自己的__instanceDict表里的
local function _setClassMetamethods(klass)
--遍历元方法表,就是下面自己建立的那个表,里面都是元方法字符串
for _,m in ipairs(klass.__metamethods) do
--对于每一个元方法名字,在自己表内建立对应的函数,函数功能就是调用父类的相应同名元方法,然后返回值
klass[m]= _createLookupMetamethod(klass, m)
end
end
--传入一个表,和其父表 设置这个表的initialize函数
--注意:调用这个函数时,已经建立访问关系,所以这个函数是放在自己的__instanceDict表里的
local function _setDefaultInitializeMethod(klass, super)
--这个表的初始化函数就是调用其父类表的初始化函数
klass.initialize = function(instance, ...)
return super.initialize(instance, ...)
end
end
--用于把mixin表混合到klass表中
local function _includeMixin(klass, mixin)
--确保mixin为表
assert(type(mixin)=='table', "mixin must be a table")
--遍历mixin表里的所有成员,把不是include和static的成员都加到klass里面
for name,method in pairs(mixin) do
if name ~= "included" and name ~= "static" then klass[name] = method end
end
--如果mixin有static表
--遍历mixin的static表,把其中的所有成员放到klass的static表中
if mixin.static then
for name,method in pairs(mixin.static) do
klass.static[name] = method
end
end
--如果mixin的include字段为函数,调用
if type(mixin.included)=="function" then mixin:included(klass) end
klass.__mixins[mixin] = true--mixins表记录下来合起混合的
end
--Object表的建立,作为一个全局的类表
Object = _createClass("Object", nil)
--static的__metamethods 里面都是字符串名 来标示元方法,子类表创建时,用来遍历创建相应函数
Object.static.__metamethods = { '__add', '__call', '__concat', '__div', '__le', '__lt',
'__mod', '__mul', '__pow', '__sub', '__tostring', '__unm' }
--self传入调用的那个类表,根据这个类表创建一个对象表
function Object.static:allocate()
--确保self为体系中创建的表,self为调用时的那个表,一直递归找上来的那个表
assert(_classes[self], "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
--新建一个对象表,这个对象表的class键指向其类表self,且这个对象表的元表为其类表的__instanceDict字段
return setmetatable({ class = self }, self.__instanceDict)
end
--表示用这个类表生成一个对象
function Object.static:new(...)
local instance = self:allocate()--根据这个类表创建一个对象表
instance:initialize(...)--调用这个新建的对象表的调用initialize函数
return instance--返回这个对象表
end
--构造一个Object的子类表
function Object.static:subclass(name)
--第一个assert 保证有self传进来
--self就为实际的那个表,不一定是Object表,可能是Object的子类表,因为子类表没有subclass函数时,会到父类表的static中找,当前这个父类表也不一定是Object
--父类表再没有递归上来,直到到这个Object的这个函数来,但此时self是那个初始调用的那个表
assert(_classes[self], "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
assert(type(name) == "string", "You must provide a name(string) for your class")
local subclass = _createClass(name, self)--创建一个新表,以self为父表 会建立subclass和slef的访问关系,并把subclass记录在全局的_Classes
--注意:由于上面已经建立了读取和设置关系,所以下面新加的方法都放在表的__instanceDict表里,而不是自身里
_setClassMetamethods(subclass)--在新表里面建立上面列的元方法,每个元方法对应功能就是调用父类的元方法
_setDefaultInitializeMethod(subclass, self)--设置新建的子类表的初始化函数,就是调用父类的初始化函数
self.subclasses[subclass] = true--在父类表的subclasses表中记录下这个子类表
self:subclassed(subclass)--调用父类表的subclassed函数
return subclass--创建完成,返回这个新建的表
end
--subclassed函数,也是空函数,暂时不知道何意义,难道为了扩展统计???
function Object.static:subclassed(other) end
--把参数传递的所有参数(都为表),混合近self中去
function Object.static:include( ... )
assert(_classes[self], "Make sure you that you are using 'Class:include' instead of 'Class.include'")
--遍历参数的,把每个混合井self中去,然后返回self
for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
return self
end
--初始化函数,Object的初始化函数就为空
function Object:initialize() end
function Object:__tostring() return "instance of " .. tostring(self.class) end
--声明一个类 name类名 super父类名 ...构造参数
--注意着只是定义类,用来在这个体系中创建每个表自己的关系,来构造成类继承的结构
function class(name, super, ...)
super = super or Object --未指定父类 就用Object
return super:subclass(name, ...)
end
--判断obj是否由aClass生成的表
function instanceOf(aClass, obj)
--若aClass不是这个体系中的,或obj根本就不是表,或??
if not _classes[aClass] or type(obj) ~= 'table' or not _classes[obj.class] then return false end
if obj.class == aClass then return true end
return subclassOf(aClass, obj.class)
end
--判断other是否为aClass的父类
function subclassOf(other, aClass)
--如果other或cClass有一不是这个体系建立的表,或aClass没有super父表,则返回false
if not _classes[aClass] or not _classes[other] or aClass.super == nil then return false end
--否则要么aClass的直接父类就是other,要么递归上去,看aClass的父类的父类是否是other
return aClass.super == other or subclassOf(other, aClass.super)
end
function includes(mixin, aClass)
if not _classes[aClass] then return false end
if aClass.__mixins[mixin] then return true end
return includes(mixin, aClass.super)
end
--[[
总结
体系成员
当前文件一个local _classes表,所有在这个体系中创建的类表,都会记录在其中
全局的一个OBject类表,作为基类
OBject的函数时定义在其static表内的
分为类表和对象表
类表时由上面的class函数来建立,描述的是一个类,class创建类表时还能指定父类,来建立类表间的继承关系
对象表,由一个类表的调用new函数得到,会新建一个表,并调用其初始化函数,真正使用的是对象表
由Class函数创建可以看出,这是一个单继承体系模型
Mixin?意义待分析
体系中每个类表成员和作用
name 字符串,表示这个类的名字
super 表,指向这个表的父类表
static 表,静态功能表,实现了建立体系的基础函数,除了Object外,其他默认都是空的
__mixins 表,记录所有和这个表混合的表
__instanceDict 表,类实现字典,放置所有给当前类表定义的函数和变量
subclasses 表,以子类表作为键,记录这个表的所有子类表
类表的读取和设置关系
设当前类表为A,A的直接基类表为B,B的直接基类表为C,以此类推设最上层为Z
联通属性如下
1 每个类表自身和其static表是__index联通的
2 每个类表自身和其__instanceDict表是__newindex联通的
3 每个类表的static表和其自身的__instanceDict表是__index联通的
4 每个类表的__instanceDict表和其直接基类表的__instanceDict表是__index联通的
访问A时
读取A
若A自身没有,到A的static表中读(1),也没有到A的__instanceDict表中读(3),也没有递归往直接基类的__instanceDict表读(4),递归到最上Z的__instanceDict表(4)
也没有,此时到A直接父类B的static表中找,再没有到B的__instanceDict表找(3),然后同上递归到最上Z的__instanceDict表(4)(即,这里实际为不必要的)
此时寻找结束
所以有
5 读取顺序,查找自己,自己的static表,自己的__instanceDict表,继承体系中所有基类的__instanceDict表,直接基类的static表
设置A
若A自身没有,到A的__instanceDict表去设置(2),然后结束
所以有
6 设置顺序,查找自己,和自己的__instanceDict表
所有类表不会在自身表内设置新值,新值是保存在自己的__instanceDict表中
建立初始化和元方法函数(注意:这些函数在类表的__instanceDict里)(OBject的initialize方法也在其自身的__instanceDict表里)
遍历元方法名,在自己表内建立对应键的函数,函数功能就是调用父类的相应同名元方法,然后返回值
如上访问关系建立后,给新类表,自身一个initialize函数,函数功能就是调用其父类的initialize函数
如上设置属性可知:是为了给表定义这些函数时,是直接在表里,不会到其__instanceDict表去设置
所以有
7 Object的static表里实现了基础的体系函数,而其他体系中的表默认static里是空的
除了体系中构建时给你类表里添加东西外,其他所有你新加的东西都会放在自己的__instanceDict表里,除非你显示指定位置
对象表和类表的关系
对象表通过体系中相应的类表调用new函数实现
会新建一个空表,给空表一个键class指向创建他的那个类表,同时把这个类表的__instanceDict表设置为这个新建对象表的元表
所以:
新建的对象表,默认自身只会含有一个键class指向创建他的那个类表,新建对象表的元表是创建他的那个类表的__instanceDict表
读取,
读取这个对象表,自己没有就到class指向的类表的的__instanceDict表中找,然后递归向上找__instanceDict表(4)
设置,
设置只会设置自己
对象表一般不用设置,且设置的话不会影响到其类表,只是在对象表自身里面
类体系实现
定义类时
使用class和父类建立访问关系,并在自己的__instanceDict里,建立默认的initialize函数和元方法函数
所有非明确指定的定义的新函数和变量都放在自己的__instanceDict表里
新建对象的初始化
创建对象时,由类表new,先创建一个对象表,然后以这个对象表去调用initialize,对象表实际没有initialize函数,所以访问的是类表的__instanceDict里找
而所有类的实现方法都是在__instanceDict表里的,所以就是以这个对象表作为self去调用类表的initialize函数,形成初始化
方法的继承
访问对象表方法时,没有到其类表的__instanceDict里找,然后递归向上__instanceDict(找),所以一个对象表,如果自己没有,就能用其所有基类表
的方法和变量
修改的屏蔽
对类表进行设置,仅仅在自己的__instanceDict表里,设置,不会影响到父类表
对对象表进行设置,仅仅是对对象表自己进行设置,不会影响到其类表
(这里有个迷惑,因为类和对象都是由表来模仿的,这里的对象还是表,还可以给自己添加变量,在C++模型中确不会有这个概念)
方法的覆盖
由于是由下到上找,找到即停,所以子类表的方法和变量会覆盖,其父类表的方法和变量
方法的重载
如果在同一层次找到多个同名的函数,此时???
Mixin作用
用来模仿多继承吗?待分析?
使用
--]]
middleclass.lua分析
最新推荐文章于 2023-04-29 16:58:10 发布