LUA 構造類

15年11月寫的這份代碼,現在開源出來作爲技術文檔,希望大家能夠看到幫助更多的人清晰的理解LUA元表。

1.首先,是我設計類的整體構造,解析給大家看,需要考慮對象創建出來不能夠再去執行 new 等關鍵詞,爲此我爲其添加了索引保護代碼。

--[[
	@格式
--]]

--[[
	Proto = {
		__index = <Proto>,
		__metatable = <string>,
		__add = <function>,
		__tostring = <function>
		<metatable> = {
			__metatable = <string>,
			__tostring = <function>
		}
	}

	Class = {
		__index = <function>,
		__newindex = <function>,
		__metatable = <string>,
		__className = <string>,
		__prototype = <Proto>,
		__isInherit = <boolean>,
		new = <function>,
		super = <table>,
		init = <function>,
		<metatable> = <Proto>
	}
	
	instance = {
		class = <Class>,
		<metatable> = <Class>
	}
--]]

2.接下來是真正的安全的類的代碼。

--[[
	@關鍵字 class
	@參數 className <string>
	@參數 super <table>
--]]

class = function (className)
	local newProto = function ()
		local Proto = setmetatable({}, {
			__metatable = "Warning: can't change proto",
			__tostring = function ()
				return "proto"
			end
		})
		
		Proto.__metatable = "Warning: can't change class"
		
		Proto.__index = function (table, key)	--保護數據
			local protectList = {"__index", "__metatable", "__add", "__tostring"}
			
			if table.__prototype then
				for _, value in pairs(protectList) do
					if key == value then
						return nil
					end
				end
			end
			
			return Proto[key]
		end
		
		Proto.__add = function (first, second)
			local checkSuper; checkSuper = function (super, second)	--檢測first.super是否存在second
				for __, value in pairs(super) do
					if value == second then
						return true
					end
					
					if value.super then
						if checkSuper(value.super, second) then	--遞歸檢測
							return true
						end
					end
				end
				return false
			end
			
			local addSuper = function (first, second)
				table.insert(first.super, second)	--添加super
				
				for key, value in pairs(second) do	--添加方法
					if not first[key] then
						first[key] = value
					end
				end
				
				return first
			end
			
			if type(second) ~= "table" then	--檢測類型
				print("Error : super is not class")
				return nil
			end
			
			if not second.__isInherit then	--不可繼承
				print("Warning : [" .. second.__className .. "] is can't inherit")
				return first
			end
			
			if first.super then	--檢測super是否存在
				if checkSuper(first.super, second) then	--檢測second是否被繼承
					print("Warning : [" .. second.__className .. "] is already inherit")
					return first
				end
			else
				first.super = {}
			end
			
			if second.__prototype then	--是否爲class
				first = addSuper(first, second)
			else
				for _, value in pairs(second) do
					if value.__prototype then
						first = addSuper(first, value)
					else
						print("Error : super is not class list")
						return nil
					end
				end
			end
			
			return first
		end
		
		Proto.__tostring = function (table)
			return "class: " .. table.__className
		end
		
		return Proto
	end
	
	local Proto = newProto()	--構造proto
	
	local Class = setmetatable({}, Proto)
	
	Class.__prototype = Proto
	Class.__metatable = "Error: can't change instance"
	Class.__className = className
	Class.__isInherit = true	--可否被繼承
	
	Class.__index = function (table, key)	--保護數據
		local protectList = {"new", "super", "init", "__index", "__newindex", "__prototype", "__metatable", "__className", "__isInherit"}
		
		if table.class then	--是否爲實例
			for _, value in pairs(protectList) do
				if key == value then
					return nil
				end
			end
		end
		
		return Class[key]
	end
	
	Class.__newindex = function (table, key, value)
		print("Error: can't change instance")
	end
	
	Class.new = function (...)
		local init; init = function (class, ...)
			local super = class.super
			
			if super then
				for _, value in pairs(super) do
					init(value, ...)	--遞歸初始化super
				end
			end
			
			if class.init then
				print(class.__className .. " init")
				class:init(...)
			end
		end
		
		local instance = {
			class = Class
		}
		
		setmetatable(instance, Class)
		init(instance.class, ...)	--初始化實例
		
		return instance
	end
	
	return Class
end

3.測試類及其對象

local A = class("A")

A.init = function(self)
	print("A:init")
	self.test = 0
end

A.Test = function(self)
	print("Test", self.test)
end

local B = class("B") + A

B.init = function(self)
	print("B:init")
	print(tostring(self.super))
	self.test = 1
end

B.Print = function(self, ...)
	for _, value in ipairs(arg) do
		print(value)
	end
end

local b = B.new()
b:Test()
b:Print("a")

print(tostring(b.class))





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章