lua的面向對象實現


  百度搜索一下,給出出的解決方案和學習帖子很多,可是我還是有很多的問題!

(1)什么是面向對象?

(2)lua中怎么實現面向對象?

(3)什么樣的實現既簡單又能完成我的功能?

(4)一定要按照c++的方式實現類的繼承嗎?

  能力有限,在學習lua面向對象的時候我比較喜歡兩種實現方式:

1. 簡單粗暴的實現

參考[1]:參考同事的方法,如果借鑒、轉載請注明

  在lua中,我們知道table是萬能的一個類型,當我們用table實現一個基類和子類的時候,他們都是確確實實存在的一個個table,都是有地址的。不會說像c++一樣,類定義是類定義,只有new出來才是真正可以使用的,而lua卻不是這樣。所以,最簡單的一種方法就是,每次繼承基類的時候,直接copy基類的所有內容,函數除外,其他的成員都重新復制一遍,如果是table的話重新構建一個,並且把內容拷貝過來。代碼如下:

--lua面向對象:簡單粗暴的實現
function copytable(tbArg)
    local tbCollsion = {}
    
    --local的作用域問題
    local copy    
    copy = function (obj)
        if type(obj) ~= "table" then
            return obj;
        end
        --檢查是否有嵌套循環的table
        if tbCollsion[obj] then
            return tbCollsion[obj];
        end
        
        local tbNew = {}
        tbCollsion[obj] = tbNew;
        --遞歸復制
        for k, v in pairs(obj) do
            tbNew[k] = copy(v);
        end
        --復制完之后,元表關系也要保留下來
        return setmetatable(tbNew, getmetatable(obj))
    end

    return copy(tbArg);
end

function inherit(tbBase, tbClass)
    --復制基類
    local tbNew = copytable(tbBase)
    
    
    local tm = {}
    tm.__index = tbClass;
    setmetatable(tbNew, tm)
    
    --修改tbBase為tbClass中的成員或者新增加tbClass中的成員
    if tbClass then
        for k, v in pairs(tbClass) do
            tbNew[k] = v
        end
    end

    return tbNew;
end
--使用
local tbObject = {}
local tbFruit = inherit(tbObject)
local tbApple = inherit(tbFruit)
local tbBanana = inherit(tbFruit)
local tbBanana1 = inherit(tbFruit)
local tbBanana2 = inherit(tbFruit, tbBanana1)

 

優點:

(1)好理解

(2)好用,不會出現共用一個table引用,導致其中一個修改影響了另外一個

(3)共享函數引用

缺點:

(1)真正意義上的面向對象,繼承等概念不清晰

(2)一個子類new多個對象的概念是沒有的,和繼承已經混在了一起,所以如果要實現new多個對象的話,有代碼冗余

 

2. 概念意義上的實現

參考[2]:雲風的blog,如果借鑒、轉載請注明

  這種從概念上實現面向對象的方法做到以下幾點:

(1)有類定義和對象的概念,類定義通過new來創建對象,並且同時調用自己的構造函數

(2)子類可以訪問基類的成員函數

(3)類定義不能夠調用函數(除了new之外),只有對象才能調用函數

(4)構造函數調用有和c++一樣的層級關系,先調用父類的構造函數,再調用子類的構造函數

--lua面向對象:概念意義上的實現
local _class={}
 
function class(super)
    local class_type={}
    --注意:因為重載了__newindex函數, 所以ctor不要定義為nil
    class_type.ctor=false
    class_type.super=super
    class_type.new=function(...) 
            local obj={}
            --下面的塊只做了一件事:依次從父類到當前子類調用構造函數ctor
            do
                local create
                create = function(c,...)
                    if c.super then
                        create(c.super,...)
                    end
                    if c.ctor then
                        c.ctor(obj,...)
                    end
                end
 
                create(class_type,...)
            end
            setmetatable(obj,{ __index=_class[class_type] })
            return obj
        end
    
    --新加成員:防止定義類調用函數
    local vtbl={}
    _class[class_type]=vtbl
 
    setmetatable(class_type,{__newindex=
        function(t,k,v)
            vtbl[k]=v
        end
    })
 
    --只有定義類修改了__newindex
    --vbtl只屬於定義類
    --new出來的對象共享所有定義類的引用,但獨享自己新增加的成員變量
    if super then
        setmetatable(vtbl,{__index=
            function(t,k)
                local ret=_class[super][k]
                vtbl[k]=ret
                return ret
            end
        })
    end
 
    return class_type
end

說明幾點:

(1)只有定義類修改了__newindex
(2)vbtl只屬於定義類
(3)new出來的對象共享所有定義類的引用,但獨享自己新增加的成員變量

有點:

(1)概念上更加清晰,熟悉c++面向對象的很容易了解這個繼承的關系

(2)寫法上感覺很牛逼,做到了定義不能調用函數這一點

(3)共享函數引用

缺點:

(1)概念上清晰的成本是要更多的時間去理解

(2)雖然做到了c++類定義和對象上的概念區別,但是還是有多東西沒有實現

(3)對象也可以定義自己的函數,這一點就直接打破了區分定義和對象的本源,但是價值還是有的

(4)所有new出來對象共享類定義的引用對象,包括不需要復用的函數和table。由此多個對象共享一個定義的table很是個問題!

* 針對(4),可以通過實現定義的init函數,在init函數給不同的對象初始化不同的數據,即使是table!

 

參考:

[1]同事

[2]http://blog.codingnow.com/cloud/LuaOO


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM