Lua物件導向設計

來源:互聯網
上載者:User

標籤:style   blog   java   color   使用   strong   

  物件導向的基礎是類,但Lua中沒有提供類的概念,所以我們需要利用Lua現有的機制來實作類別似於類的有關oop的一整套概念。基本方案是使用table來實作類別機制,並且結合使用self參數和冒號操作。我們先來看看self參數和冒號操作符的用法:

  self參數的使用是很多物件導向語言的要點,大多數OO語言將這種機制隱藏起來,這樣程式員不必聲明這個參數(雖然仍然可以在方法內使用這個參數)。Lua也提供了通過使用冒號操作符來隱藏這個參數的聲明(通過冒號來聲明函數)。先來看下這段代碼(這裡面還不涉及到類的定義,只是純粹為瞭解釋self和冒號操作):

Account = {balance = 0}function Account.withdraw(obj, v)    obj.balance = obj.balance + venda = Accounta.withdraw(a, 100)print(a.balance)

  也可以將函數寫成這樣(將obj換成self能更好的表達出該參數的語義):

function Account.withdraw(self, v)    self.balance = self.balance + vend

  self本身是一個Lua的保留字,為了不必給每個函式宣告都加上self,Lua提供了冒號操作符:

function Account:withdraw (v)    self.balance = self.balance - vend

  定義函數時將點改成冒號,函數體內部直接用self參數訪問對象自己(self參數表示表自己,也就是對象本身)。同時函數調用也有兩種寫法,並且這兩種寫法是通用的:

a.withdraw(a, 100)a:withdraw(100)

  點操作需要顯示傳入調用者自身。實際上,冒號的效果相當於在函數定義和函數調用的時候,增加一個額外的隱藏參數。這種方式只是提供了一種方便的文法,並沒有什麼新的內容。我們可以使用dot文法定義函數而用冒號文法調用函數,反之亦然,只要我們正確的處理好額外的 參。

   Lua中的表其實是一個對象。我們定義一個表作為原型(相當於類定義),然後其他的對象(也是一個表)通過metatable和__index機制來訪問原型表中的成員。下面看下類的實現:

Account = {balance = 0}--將表自己做成metatable,或者也可以在表中加入一個mt成員來作為metatablefunction Account:new(o)    o = o or {}    setmetatable(o, self)    self.__index = self    return oendfunction Account:withdraw(v)    self.balance = self.balance - vendfunction Account:deposit(v)    self.balance = self.balance + venda1 = Account:new{}a2 = Account:new{balance = 100}a1:withdraw(100)print(a1.balance)print(a2.balance)

  為了簡潔,直接將類本身定為對象表的metatable。上面的new函數還是有一定的技巧性的,之前用過C++/Java等語言的人,應該不太習慣這種寫法。因為在強型別語言中,編程者會盡量避免傾向於展示技巧的寫法,而使用更簡單、可讀性更高的寫法。但在使用Lua時需要轉換一下思維,尤其是在基於Lua基礎的東西來擴充一些概念的時候,各種技巧性的東西會很常見,要習慣。

  類繼承的實現其實很簡單,直接調用基類的new操作,然後在子類中可以添加一些新的成員或方法:

-- 繼承自Account的類(其實就是一個Account對象),SpecialAcount可以重新定義繼承來的成員函數,或添加新的成員函數SpecialAccount = Account:new()-- 子類執行個體化,有趣之處是,s的metatable是SpecialAccounts = SpecialAccount:new{limit = 1000}

  可以看到,其實上面的類也是對象,只是看你怎麼去理解它,當把一個對象當做模板原型來用時,它就是一個類,但同時,它也是一個對象,很隨意有木有。

   多繼承:多繼承的想法很簡單,就是對於子類中不存在的域,在多個父類中依次尋找即可。不過此代碼有點複雜,如下所示:

Named = {name = "default"}function Named:getname() return self.name endfunction Named:setname(v) self.name = v end--k為函數名,list為父類列表search = function(k, list)    for i = 1, table.getn(list) do        local v = list[i][k]        -- 訪問第i個父類的k域,存在則返回        if v then return v end    endend-- 參數為父類列表createClass = function (...)    c = {}    -- 這裡面的k為訪問的域    setmetatable(c, {__index = function(t, k) return search(k, arg)   end})        -- 用作對象的metatable    c.__index = c    function c:new(o)        o = o or {}        setmetatable(o, c)        return o    end        return cendNamedAccount = createClass(Account, Named)obj = NamedAccount:new{name = "Paul"}print(obj:getname())

  函數search表示在父類列表list中依次尋找名字為k的域。

  函數createClass用於建立多繼承的類,參數為父類列表。可以看到對象以多繼承類為metatable,而多繼承類通過metatable在多個父類中依次尋找域。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.