Class={}; Class.classList={}; --保存全部已經定義過的類 --類的類型: 類和接口, 接口也是一種類 Class.TYPE_CLASS="Class"; Class.TYPE_INTERFACE="Interface"; function Class.isExist(className) return Class.classList[className] ~= nil; end --將定義的類註冊,防止重複定義 function Class.register(className,clazz) if(Class.isExist(className)) then return end; Class.classList[className]=clazz; end function Class.getDefinedClass(className) return Class.classList[className]; end -- 將錯誤信息返回而不是直接error, 這樣在外層再經過error的level2 拋出異常,就能更精肯定位到調用者 function Class._checkValid(class, clsType) clsType = clsType or Class.TYPE_CLASS; if(class==nil) then return clsType .. " 未定義!!"; end if(type(class)~="table") then return "\""..tostring(class).."\" 不是一個" .. clsType .."!!"; end local b = false; for k, v in pairs(Class.classList) do if(v == class) then b = true; end end if(not b) then return clsType .. " ".. tostring(class) .. " 未定義!!"; end if (clsType==Class.TYPE_CLASS and class.__classType~=Class.TYPE_CLASS) or (clsType==Class.TYPE_INTERFACE and class.__classType~=Class.TYPE_INTERFACE) then return "\"" .. class.className .. "\" 不是一個 "..clsType.."!!"; end return nil; end --定義一個類. 因爲沒法區分是沒有傳入extendsCls仍是傳入了一個錯誤的extendsCls,因此提供了define2來自動繼承自Object. 這個方法是強制傳入Object方法 --@param className 類名.字符串. --@param ... 第一個參數是 extends 父類,後面要實現的一組接口. function Class.define(className, ...) local cls = Class._define(Class.TYPE_CLASS, className, ...) if (type(cls)=="string") then error(cls, 2); end return cls; end function Class._define(clsType, className, ...) if(type(className)~="string") then return clsType.." 名稱 \""..tostring(className).."\" 無效!!"; end if(Class.isExist(className)) then return clsType.." \""..tostring(className).."\" 重複定義!!"; end local clazz={className=className, __classType=Class.TYPE_CLASS}; --保存本類須要實現的接口,且不能重複實現同一接口 local extendsCls; local arglen = select("#", ...); local err = nil; -- 說明沒有顯示傳入繼承的類 if(arglen<1) then if(className=="Object") then extendsCls = nil; else extendsCls = Object; end else extendsCls = select(1,...); err = Class._checkValid(extendsCls,clsType); if(err) then return err; end end clazz.parentClass=extendsCls; clazz.__implements={}; local _impl; for i=2, arglen do _impl = select(i, ...); --驗證接口有效性 err = Class._checkValid(_impl, Class.TYPE_INTERFACE); if(err) then return err; end --檢查接口是否重複繼承 for _,v in ipairs(clazz.__implements) do if(v==_impl) then return Class.TYPE_INTERFACE.." \"".._impl.className.."\" 重複繼承!!"; end end table.insert(clazz.__implements, _impl); end if(className=="Object") then Class.register(className,clazz); return clazz; end Class.register(className,clazz); return clazz; end --檢測當前類以及父類是否實現了相關接口的方法 function Class._checkImplements(cls, interfaces) if(#interfaces<1) then return end; local pInterface; for k,v in ipairs(interfaces) do --查找當前接口的全部方法是否被實現 Class.__checkImplements(cls, v); --查找當前接口的父級接口的全部方法是否被實現 pInterface=v.parentClass; while(pInterface) do Class.__checkImplements(cls, pInterface); pInterface=pInterface.parentClass; end end end --檢測當前類和父類是否實現了一個接口的全部方法 function Class.__checkImplements(cls, interface) local b=true; local pcls; for name, func in pairs(interface) do if(type(func)=="function") then if(cls[name] and type(cls[name]=="function")) then return end --當本類中不存在這個,則在父類中查找 pcls=cls.parentClass; while(pcls) do if(pcls[name] and type(pcls[name]=="function")) then return end pcls=pcls.parentClass; end --子類和父類中都沒找到,說明沒有實現 error("\""..cls.className.."\" 未覆蓋 \""..interface.className.."\" 中的抽象方法 "..name.."()"); end end end function Class.createObjectFromClass(class) local o={}; o.class=class; setmetatable(o,class); --設置訪問時的操做 class.__index=function(t,k) --屬性和方法從本類開始往父類逐級找 local v = nil; local pcls = t.class; while(pcls) do v = rawget(t.class, k); if(v) then return v end; pcls = pcls.parentClass; end return nil; end return o; end --驗證構造參數合法性 function Class.checkCtor(class, ...) if(class==Object or class.parentClass==nil) then return; end --產生一個無參構造. if(class._ctor == nil and class.ctor == nil) then class._ctor = function() end; end Class.checkCtor(class.parentClass); end --new一個對象的實例 function Class.new(class, ...) Class._checkValid(class); --檢查接口的實現狀況 Class._checkImplements(class, class.__implements); --若是都沒顯示指定無參構造函數,則在checkCtor()中生成一個無參的構造函數 Class.checkCtor(class, ...); -- 獲取參數的真實長度, 用來區分傳入的參數在爲nil時,究竟是調用者填寫的nil仍是系統默認的nil local arglen = select("#", ...); --若是當前類沒有有參構造,則參數必須爲空 if(class.ctor == nil and arglen ~= 0) then error("構造函數錯誤,不存在有參構造函數. Class "..class.className); elseif(class._ctor == nil and arglen == 0) then error("構造函數錯誤,不存在無參構造函數. Class "..class.className); end -- 將父類的全部定義的屬性拿出來放到一個映射表中 local attributes = {}; -- Map<類名, Map<屬名,value> > -- 將類鏈表中定義的方法作個列表存放起來. 每一個類本身定義的方法都作單獨保存,主要爲super提供 local functionsMap = {}; -- Map<類名, Map<方法名,func> > --保存最後實現的那些方法. 實現多態. functionsMap.lastFuncs = {}; --查找類鏈 local _clsListTemp = {}; local pcls=class; while(pcls~=nil) do table.insert(_clsListTemp, pcls); pcls = pcls.parentClass; end --先從上往下依次調用類鏈中的全部方法. local _cls = nil; for i = #_clsListTemp, 1, -1 do _cls = _clsListTemp[i]; functionsMap[_cls] = {}; --找出方法,保存到方法列表中 for k,v in pairs(_cls) do --原本應該檢查方法名稱是否和屬性名稱重複. java中能夠作到方法名和屬性名重複, 但lua不行,會覆蓋. --默認的無參構造函數不存起來,由於會自動都調用一次. if(type(v)=="function" and k~="_ctor" and k~="__index" and k~="__newindex") then if(k=="getter_ctor" or k=="setter_ctor" or k=="getter__ctor" or k=="setter__ctor") then error("不能將構造方法定義爲getter或setter方法!!"); end --保存對應的方法列表. 默認指向最後的實現者,但也保存每一個類中本身的那個方法,以便經過super調用的時候找到對應的方法. functionsMap[_cls][k] = v; --因爲是從上往下調用,因此子類覆蓋的方法會被正確指向. 有參構造不能覆蓋保存. if(k~="ctor") then functionsMap.lastFuncs[k] = v; end end end end local obj = {}; -- obj 是在new以後返回的一個空的代理對象, 真正的對象是這個meta,全部表象上看起來的屬性的訪問和修改也來自於這個meta. -- 這樣也方便的模擬實現了 getter 和 setter local meta = {class = class, __attributes = attributes, __functionsMap = functionsMap}; setmetatable(obj, meta); --設置鍵爲弱引用. meta.__mode="k"; --訪問屬性和方法 meta.__index = function(t, k) if(k=="_ctor") then return nil end local m = getmetatable(t); if(k=="class") then return m.class end local attr,func; --先從屬性查找 attr = m.__attributes[k]; if(attr~=nil) then return attr end -- 判斷是否有getter方法,若是有getter方法,優先調用getter方法 func = m.__functionsMap.lastFuncs["getter_"..k]; if(func~=nil) then return func(t); end --方法. func = m.__functionsMap.lastFuncs[k]; if(func ~= nil) then return func end --若是元表對象中找不到,則從類鏈中查找. 在java中的表現爲用實例化對象去訪問它的類的靜態屬性或方法. local pcls = m.class; while(pcls~=nil) do attr = pcls[k]; if(attr~=nil) then --若是是方法, 進行一次代理訪問方法, 不會把這個方法返回出去. --由於外部多是冒號訪問, 而類的靜態方法只能是點號訪問, 這樣在那些方法內部使用self會出錯. 變相的作了限制 if(type(attr) == "function") then return attr(); end return attr; end pcls = pcls.parentClass; end return nil; end --修改屬性和方法 meta.__newindex = function(t, k, v) if(k=="class") then error("class 是隻讀屬性. \""..m.class.classNa.."\" !!"); end if(k=="ctor" or k=="_ctor") then error("不能將構造方法定義爲屬性!!"); end local m = getmetatable(t); if(m.__functionsMap.lastFuncs[k] and v~=nil) then --判斷這個方法是不是一個getter,setter方法. 若是是,則不能容許屬性存在重複定義 local stind,endind = string.find(k,"getter_"); local subname = nil; if(stind~=nil) then subname = string.sub(k,endind+1); else stind,endind = string.find(k,"setter_"); if(stind~=nil) then subname = string.sub(k,endind+1); end end if(subname) then error("不能從新定義Class \"".. m.class.className .."\" 的getter, setter方法 \""..subname.."\" !!"); --else -- error("不能從新定義Class \"".. m.class.className .."\" 的方法 \""..k.."\" !!"); end end --改變的值不是一個方法. 就添加到屬性列表中 if(type(v)~="function") then -- 判斷是否有setter方法,若是有setter方法,優先調用setter方法 local func = m.__functionsMap.lastFuncs["setter_"..k]; if(func~=nil) then return func(t, v); end m.__attributes[k] = v; return; else -- error("不能爲Class \"".. m.class.className .."\" 的實例動態添加方法 \""..k.."\" !!"); m.__functionsMap.lastFuncs[k] = v; end end --因爲上面已經找出了全部方法, 因此在構造函數中就能夠訪問那些方法了. 也就是在構造函數中執行一些邏輯. for i = #_clsListTemp, 1, -1 do _cls = _clsListTemp[i]; --產生_cls的臨時對象 local __o = Class.createObjectFromClass(_cls); --這裏用點號訪問,並傳入了代理的obj對象,這樣在_ctor定義的屬性就會保存到obj元表對象meta的 attributes中(經過上面的__newindex操做). --若是在_ctor中初始調用邏輯方法,也能在obj元表meta的functionsMap 中正確訪問到. --若是出現重複定義屬性, 這裏沒有使用像java同樣的方式保存在不一樣類中定義的相同屬性的副本. --有點像actionscript中同樣不能重複定義(as中父類的屬性可見性要比子類小,不然就報重複定義的編譯級錯誤). --但這裏沒有實現 private 這樣的可見性, 因此所有視爲 public. 那天然不容許重複定義屬性. --理論上應該作一次檢查,若是重複定義要報錯.但lua沒有像其它預編譯語言的定義屬性的概念, --而且我沒法知道子類在構造方法內部寫self.xx=value 時究竟是定義這個屬性仍是更改它的值(若是它已經在父類中定義了) --因此這裏統一處理,不存在就定義,存在就覆蓋. --而且因爲ctor 不能被覆蓋,在上面存儲方法時已經屏蔽了ctor方法,但_ctor方法中可能會調用ctor方法,且此時只能訪問本身這個類中的ctor方法, --那就要將這個存在的ctor從__o中取出來放到obj的元表中臨時保存起來,再調用_ctor時,若是內部又要調用ctor纔不會出錯,且能正確調用到類鏈中對應位置的ctor. if(__o.ctor~=nil) then getmetatable(obj).__functionsMap.lastFuncs.ctor=__o.ctor; end --自動調用了一次每一個類的無參構造函數. --這裏和java不同, java是當new時不傳參數時,纔會調用無參構造,且若是這個無參構造裏沒有顯示寫super,又會自動調用父類的無參構造. --但在這裏我沒法知道到底有沒有在代碼內部顯示寫super, 就不知道是否該自動調用父類的無參構造. --若是不自動統一調用,那每一個子類都要顯示寫上無參構造函數並在內部寫self:super(class,"_ctor"). --爲了業務統一方便,這裏自動調用, 因此在無參構造函數裏儘可能不要包含對其它函數的調用,省得邏輯重複. if(__o._ctor~=nil) then __o._ctor(obj); end --若是子類沒有定義他本身的ctor,但子類的_ctor中又寫self:ctor()這樣的語句,就可能會調用到父類的ctor方法.這是錯誤的. --因此無論_ctor內部是否調用過了ctor,以後都要將臨時保存的ctor清除。 if(__o.ctor~=nil) then getmetatable(obj).__functionsMap.lastFuncs.ctor=nil; end end --若是存在參數就調用本類的有參的構造ctor(). 父類的有參構造不會被自動調用,只有子類顯示寫self:super(class, k, ...); local arglen = select("#", ...); -- 只有調用者真正的寫了參數,即便是nil,才能調用有參構造 local ctorFunc = arglen~=0 and getmetatable(obj).__functionsMap[class].ctor; if(ctorFunc) then ctorFunc(obj, ...); end return obj; end --假如這個super是一個簡單實現,沒有第一個class做爲參數,出現的狀況是: --設有類 A <- B <- C <- D 其中在A類中定義了func1, 在C類中覆蓋了func1,並在方法代碼內部簡單寫super(self,"walk"). --如今Class.new(D),並經過D的實例調用func1. 正確的邏輯應該是訪問到C 的func1,而後又訪問到A 的func1. --但方法都是冒號訪問, 因此用C 類中的func1裏的super(self,"walk")這個self的引用其實是D 的實例. 若是不進行判斷,就會陷入死循環. --這裏傳入cls就是明確告訴我當前覆蓋walk方法的類是哪一個, 再從cls的父類繼續找到A. --若是不傳入cls, 那我沒法知道當前super代碼位於哪一個類裏面, 就可能致使陷入循環(B和C的walk方法裏都寫生super時就會陷入死循環) --因此第一個參數class只能經過外部顯示傳入. function super(cls, t, k, ...) Class._checkValid(cls); if(instanceof(t,Object)==false) then error("參數類型錯誤. 不是一個正確的Object實例!!"); end Class._checkValid(t.class); if(type(k)~="string") then error("參數類型錯誤. 使用 super 訪問時,只能傳入屬性或方法的字符串名稱!!"); end local m = getmetatable(t); local pcls = cls.parentClass; local func = nil; if(pcls==nil) then error("訪問 Class \""..cls.className.."\" 的父類不存在!!"); end if(k=="ctor") then func = m.__functionsMap[pcls][k]; if(func~=nil) then return func(t, ...); else error("訪問 Class \""..t.class.className.."\" super的方法 \""..k.."\" 不存在!!"); end end --屬性. 這裏沒有像java同樣也保存了父類的相同名稱的屬性的副本. 即用super時也會獲得這個屬性最後被改過的那個值 local attr = m.__attributes[k]; if(attr~=nil) then return attr; end --檢查t的class中是否有k方法 while(pcls~=nil)do func = m.__functionsMap[pcls][k]; if(func~=nil) then return func(t, ...); end pcls = pcls.parentClass; end error("訪問 Class \""..t.class.className.."\" super的方法 \""..k.."\" 不存在!!"); end local _instanceof; -- 一個對象是不是一個類或接口的實例 function instanceof(obj,class) if(obj==nil or type(obj)~="table" or obj.class==nil) then -- print("參數錯誤 1, 不是一個對象!!"); return false; end Class._checkValid(class); if(rawget(class,"__classType")==nil) then error("參數錯誤 2,不是一個類!!"); end if(class==Object) then return true end local ocls=obj.class; if(ocls==class) then return true end local pcls,b=nil,false; --若是是個類,則查找父類 if(class.__classType == Class.TYPE_CLASS) then pcls=ocls.parentClass; while(pcls~=nil) do if(pcls==class) then return true end pcls=pcls.parentClass; end --若是是個接口,則在本類和父類的全部接口中查找 elseif(class.__classType == Class.TYPE_INTERFACE) then b=_instanceof(ocls,class); if(b) then return true end pcls=ocls.parentClass; while(pcls~=nil) do b=_instanceof(pcls,class); if(b) then return true end pcls=pcls.parentClass; end end return false; end _instanceof=function(cls,class) local interfaces,pInterface,b=cls.__implements,nil,false; if(#interfaces<1) then return false end --可能會重複查找相關接口 for k,v in ipairs(interfaces) do if(class==v) then return true end --查找當前接口的父級接口的全部方法是否被實現 pInterface=v.parentClass; while(pInterface~=nil) do if(class==pInterface) then return true end pInterface=pInterface.parentClass; end end return false; end ----------------------------------------- --Object Object=Class.define("Object"); function Object:_ctor() --print("Object _ctor"); end --提供一個便捷訪問. 每一個類的實例就能夠經過 self:super(cls,k,...)來訪問 function Object:super(cls, k, ...) super(cls, self, k, ...); end Class.define("Class"); --定義class自己 --接口 Interface=Class.define("Interface"); function Interface.define(interfaceName, ...) local arglen, cls,extendsInterface; arglen = select("#", ...); if(arglen<1) then cls = Class._define(Class.TYPE_INTERFACE, interfaceName); else if(arglen>1) then error(Class.TYPE_INTERFACE.." 只能繼承一個接口!!", 2); end extendsInterface = select(1, ...); Class._checkValid(extendsInterface, Class.TYPE_INTERFACE); cls = Class._define(Class.TYPE_INTERFACE, interfaceName, extendsInterface); end if (type(cls)=="string") then error(cls, 2); end cls.__classType=Class.TYPE_INTERFACE; return cls; end -- IPerson = Interface.define("IPerson"); -- function IPerson.walk() end -- function IPerson.talk() end -- Role = Class.define("Role", Object, IPerson); -- function Role:walk() -- print("walk"); -- end -- function Role:talk() -- print("talk"); -- end -- Monster = Class.define("Monster", Role); -- Class.new(Monster):walk(); -- People = Class.define("People", Role); -- local p = Class.new(People); -- p:walk(); -- p:talk(); --=============== 模擬測試 ================= --[[測試繼承和接口 IPerson = Interface.define("IPerson"); function IPerson.walk() end Role = Class.define("Role", Object, IPerson); function Role:walk() print("walk"); end Monster = Class.define("Monster", Role); Class.new(Monster):walk(); -- ]] --[[測試構造函數 Role = Class.define("Role"); function Role:_ctor() self:ctor("defName"); end function Role:ctor(name) self.name=name; self:walk(); end function Role:walk() print(self.name .." walk"); end Monster = Class.define("Monster", Role); --這裏monster沒有定義任何構造函數,會自動產生一個無參構造函數. 詳見Class.checkCtor()方法. Class.new(Monster); --]] --[[測試構造函數2 (這是一個注意的地方) Role = Class.define("Role"); function Role:_ctor() self:ctor("defName"); end function Role:ctor(name) self.name=name; self:walk(); end function Role:walk() print(self.name .." walk"); end Monster = Class.define("Monster", Role); function Monster:ctor(name) self:super(Monster,"ctor",name); end Class.new(Monster,"m1"); 這裏打印的結果是: defName walk m1 walk 這是一個相對於java來講錯誤的結果. 在java裏,只會打印出m1 walk. 由於這裏我默認自動調用了類鏈中的每一個無參構造 --]] --[[測試方法的重寫與super Role = Class.define("Role"); function Role:ctor(name) self.name=name; end function Role:walk() print(self.name .." role walk"); self:speak(); end function Role:speak() print("role speak"); end Monster = Class.define("Monster", Role); function Monster:ctor(name) self:super(Monster,"ctor",name); end function Monster:walk() print("monster walk"); self:super(Monster,"walk"); end function Monster:speak() print("monster speak"); end Class.new(Monster,"m1"):walk(); 結果以下: monster walk m1 role walk monster sepak 即,在父類中調用的speak()方法被正確的指向到了子類, 經過super也能正確的訪問到父類的walk方法 --]] --[[測試getter, setter(相似as3,c#,vb.net等語言中的 get,set 方法) --這裏我規定的是,以getter_,setter_開頭的方法會做爲getter和setter方法來解析 Role = Class.define("Role"); function Role:_ctor() self._name=nil; end function Role:setter_name(v) self._name=v; end function Role:getter_name() return self._name; end local r = Class.new(Role); r.name="r1"; print(r.name); 結果以下: setter_name getter_name r1 說明正確的訪問到了getter和setter,爲屬性的訪問提供了更多的邏輯操做 --]] --[[更多的測試 Role = Class.define("Role"); Role.name="static name"; Role.age=10; function Role:_ctor() print("role self: ",self); self.age=20; end Monster = Class.define("Monster", Role); function Monster:_ctor() print("monster self: ",self); end local m = Class.new(Monster); print(m.name, Role.name, m.age, Role.age); 結果以下: role self: table: 00437678 monster self: table: 00437678 static name static name 20 10 能夠看到在Role中的self和Monster是一個對象.java中也是如此.詳見358行 經過實例對象也能訪問到Role的靜態屬性name,也打印出了正確的結果,這點和java同樣. 但對於age卻不同, java中會報一個錯誤,由於重複定義了age, 這裏爲了節約性能,我沒有作過多的重複定義的檢查.因此看到的結果是self訪問到實例中的age.因此這種狀況只能本身避免去寫. --]]