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))





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