lua 面向对象类封装

LuaObject = {}

function LuaObject.extends(o)
    o = o or {}
    local obj = {}
    setmetatable(obj, {
        __index = o
    })
    return obj
end

local function LuaObjectClone(obj, objMap)

    if not obj or type(obj) ~= "table" and type(obj) ~= "userdata" then
        print(string.format("传入对象类型【%s】,请传入Lua表对象", type(obj)))
        return nil
    end
    local newObj = {}
    if not objMap then
        objMap = {}
    end

    -- local newMeta = {}
    -- if not objMap then
    --     objMap = {}
    -- end

    local meta = getmetatable(obj)

    if meta then
        local metaNew = {}
        for key, value in pairs(meta) do
            if type(value) == "table" or type(value) == "userdata" then
                local newtb = LuaObjectClone(value, nil)
                metaNew[key] = newtb
            else
                metaNew[key] = value
            end
        end

        setmetatable(newObj, metaNew)
    end

    for key, value in pairs(obj) do
        if type(value) == "table" or type(value) == "userdata" then
            local tbTemp = objMap[tostring(value)]
            if not tbTemp then -- 如果要拷贝的table不是当前table或者没有拷贝过的类才能拷贝,否则直接赋值(因为已经拷贝了)

                local tb = LuaObjectClone(value, objMap)
                objMap[tostring(value)] = tb -- 存储当前已拷贝的table ,防止类相互嵌套死循环
                
                newObj[key] = tb
            else
                newObj[key] = value
            end
        else
            newObj[key] = value
        end
    end
    return newObj
end
function LuaClone(obj)
    return LuaObjectClone(obj)
end

function LuaNew(obj)
    if not obj or type(obj) ~= "table" and type(obj) ~= "userdata" then
        print(string.format("传入对象类型【%s】,请传入Lua表对象", type(obj)))
        return nil
    end
    local tb = Extends(obj)
    return LuaObjectClone(tb)
end

local metatableLuaObject = {
    __call = function(_, newTb)
        if not newTb or type(newTb) ~= "table" and type(newTb) ~= "userdata" then
            print(string.format("传入对象类型【%s】,请传入Lua表对象", type(newTb)))
            return nil
        end
        local obj = {}
        local newTable = {
            Base = newTb,
            membersMap = {},
            Clone = function()
                return LuaObjectClone(obj)
            end
        }
        local metatable = {
            __index = function(bt, name) -- 访问继承类不存在的此字段时调用
                if type(newTb) == "userdata" then
                    local member = newTb[name]
                    if not member then
                        print(string.format("<color=#ff0000ff>用户数据,获取此【%s】成员不存在</color>",
                                  name))
                    end
                    if type(member) == "function" then
                        return function(self, ...) -- 替换:语法糖的self
                            member(newTb, ...)
                        end
                    end
                else
                    return newTb[name]
                end
            end

        }
        setmetatable(newTable, metatable)

        local basemetabable = {
            __index = newTable,
            __newindex = function(bt, key, value) -- 设置继承类不存在的此字段时调用
                if type(key) == "string" and key == "Base" then
                    print("禁止设置Base字段,此字段为基类,保留字段")
                else
                    if type(value) == "function" or type(value) == "thread" then -- 防止继承类把基类方法覆盖,只有非方法成员才能给基类复制
                        rawset(bt, key, value)
                    else
                        local baseValue = newTb[key]
                        -- --类型匹配
                        -- if type(value) ==type(baseValue) then
                        --     -- body
                        -- end
                        if baseValue then
                            if not value then
                                if not newTable.membersMap[key] then
                                    newTable.membersMap[key] = key
                                end
                               
                            end
                            newTb[key] = value
                        else
                            local memberName =
                                newTable.membersMap[key]    -- 存储基类成员名称  ,保证基类成员完整性,同时确定赋值到基类还是派生类(原因时nil会删除成员)
                                                            -- 存储基类成员名称  ,保证基类成员完整性,同时确定赋值到基类还是派生类(原因时nil会删除成员)
                                                            -- 存储基类成员名称  ,保证基类成员完整性,同时确定赋值到基类还是派生类(原因时nil会删除成员)
                            if memberName then
                                newTb[key] = value
                            else
                                rawset(bt, key, value)
                            end
                        end

                        -- if baseValue  then         --只有基类存在当前值且类型相同时,才能给基类赋值,nil不能给基类存在的值赋值,保证基类完整性
                        --     if type(baseValue) =="string" then
                        --         newTb[key]= value or ""
                        --     elseif type(value) ==type(baseValue) then
                        --         newTb[key]= value
                        --     else
                        --         rawset(bt, key, value)
                        --     end
                        -- else
                        --     rawset(bt, key, value)
                        -- end
                    end

                end
            end
        }

        setmetatable(obj, basemetabable)
        return obj
    end
}

local function initExtends()
    Extends = {}
    setmetatable(Extends, metatableLuaObject)
end

initExtends()


------------------------测试代码-----------------------------------------------
local tb = {
    name = "zzg",
    number = 111111111,
    Info = {
        aihao = "game"
    }
}

print("-----------------------------------------------------------------------")
local netT = Extends(tb)
netT.NewName = "zzg1"
netT.name = "dddddd"
netT.Base = ""

netT.name =nil
netT.name = "zzg1"
print("----------", netT.NewName)
print("----------", netT.name)
print("----------", tb.name)

print("-----------------------------------------------------------------------")

local tbClone = LuaClone(tb)
print("start ---原始table的name值", tb.name)
print("start ---克隆table的name值", tbClone.name)

print("-----------------------------------------------------------------------")

print("原始table的name值", tb.name)
print("克隆table的name值", tbClone.name)
print("-----------------------------------------------------------------------")

local t = LuaNew(tb)
print(t.name)
local tb = {
 a=7,
 b = 20,

}
function tb:CL(obj)
    self:PR(obj)
end
function tb:PR(str)
    print(str..tostring(self.a+self.b))
end

local ex = LuaClone(tb)

ex.a=56
tb:CL("ssddd")
ex:CL("dddddddddd")

return LuaObject

Lua  对象实例化及克隆 

 

 

1.此脚本提供全局Extends()对象继承接口

如:

local tb = {

    name = "zzg",

    number = 111111111,

    Info = {

        aihao = "game"

    }

}



print("-----------------------------------------------------------------------")

local netT = Extends(tb)

netT将拥有tb所有成员

 

  1. 对象深度克隆

如果对象通过Extends()继承类将会拥有Clone()深度克隆方法

如上面的NetT可以通过NetT.Clone()获得一个新的数据完全一样对象

 

  1. 全局的lua对象深度克隆方法LuaClone()

local tbClone = LuaClone(tb)

此方法将克隆tb所有成员,并且相互独立

通过图一日志可以验证

  1. 全局的lua对象创建方法LuaNew()

此方法将会创建一个继承类并且克隆实例化此对象

local t = LuaNew(tb)

Extends和LuaNew的区别

 Extends只是继承基类,如果直接使用此方法获得类,修改基类成员时,所有继承此类的对象都将会被改动。

LuaNew方法具有继承和克隆过程,所有实例化的类都相互独立,改动基类互不影响

6.Base为基类,禁止赋值,通过基类可以访问基类

猜你喜欢

转载自blog.csdn.net/fengya1/article/details/112793684
今日推荐