Lua middleclass 詳解

A simple OOP library for Lua. It has inheritance, metamethods (operators), class variables and weak mixin support.
https://github.com/kikito/middleclass

函數(shù)功能解析

1. _createClasss(aClass, super)

返回默認(rèn)的表

  local dict = {}
  dict.__index = dict

  local aClass = { name = name, super = super, static = {},
                   __instanceDict = dict, __declaredMethods = {},
                   subclasses = setmetatable({}, {__mode='k'})  }

創(chuàng)建一個(gè)table,包含下列屬性:

  • name 類名
  • super 父類的table
  • static 靜態(tài)表
  • __instanceDict 存放類定義的屬性和函數(shù)(包含父類)
  • __decaredMethod (當(dāng)前類聲明的方法,不包含父類)
  • subclasses 子類表, 使用弱引用
 if super then
    setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) or super.static[k] end })
  else
    setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
  end

設(shè)置static表的元表為 __index = __instanceDict(或者super.static)

 setmetatable(aClass, { __index = aClass.static, __tostring = _tostring, 
 __call = _call, __newindex = _declareInstanceMethod }) 

設(shè)置類的元表:__index 為 static, __tostring => 默認(rèn)tostring,
_call =>調(diào)用static.new(), __newindex => _declareInstanceMethod

2. _includeMixin(aClass, mixin)

將一張表合并到另一張表中

  for name,method in pairs(mixin) do
    if name ~= "included" and name ~= "static" then aClass[name] = method end
  end
  • 除了"included"和"static",將mixin中的域全部賦值到aClass中(覆蓋)
  for name,method in pairs(mixin.static or {}) do
    aClass.static[name] = method
  end
  • 將mixin.static中的域,賦值到aClass.static中
  if type(mixin.included)=="function" then mixin:included(aClass) end
  • 如果mixin包含included方法,則調(diào)用mixin的included方法,參數(shù)為aClass

3. DefaultMixin

** 默認(rèn)合并表,創(chuàng)建類時(shí)自動(dòng)添加到類中**
提供如下方法:

  • __tostring 默認(rèn)tostring方法
  • initialize 初始化方法 類似于構(gòu)造函數(shù)
 isInstanceOf = function(self, aClass)
    return type(aClass) == 'table' and (aClass == self.class or self.class:isSubclassOf(aClass))
  end,
  • isInstanceOf 判斷是否是某個(gè)類的實(shí)例

為static添加方法:

allocate = function(self)
      assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
      return setmetatable({ class = self }, self.__instanceDict)
    end,
  • allocate 創(chuàng)建一個(gè)實(shí)例表
    • 添加class屬性,指向類表
    • 將類表的__instanceDict設(shè)置為元表
new = function(self, ...)
      assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'")
      local instance = self:allocate()
      instance:initialize(...)
      return instance
    end,
  • new 通過allocate創(chuàng)建表,并調(diào)用initialize方法

  • subclassed 創(chuàng)建子類后的回調(diào)

 subclass = function(self, name)
      assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
      assert(type(name) == "string", "You must provide a name(string) for your class")

      local subclass = _createClass(name, self)

      for methodName, f in pairs(self.__instanceDict) do
        _propagateInstanceMethod(subclass, methodName, f)
      end
      subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end

      self.subclasses[subclass] = true
      self:subclassed(subclass)

      return subclass
    end,

  • subclass 為類添加一個(gè)指定名字的子類,并返回子類
    • 創(chuàng)建指定名字的類,父類為自己
    • 將父類的__instanceDict中的所有域,復(fù)制到子類中
    • 子類的initialize 默認(rèn)調(diào)用父類的initialize
    • 在自己的subclass索引中,添加子類的索引
    • 調(diào)用自己的subclassed方法,參數(shù)為子類
 isSubclassOf = function(self, other)
      return type(other)      == 'table' and
             type(self.super) == 'table' and
             ( self.super == other or self.super:isSubclassOf(other) )
    end,
  • isSubclassOf 是否是指定類的子類
  include = function(self, ...)
      assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
      for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
      return self
    end
  • include 將參數(shù)合并到本類中

4. _declareInstanceMethod(aClass, name, f)

在類中添加聲明方法和屬性

local function _declareInstanceMethod(aClass, name, f)
  aClass.__declaredMethods[name] = f

  if f == nil and aClass.super then
    f = aClass.super.__instanceDict[name]
  end

  _propagateInstanceMethod(aClass, name, f)
end
  • 注冊(cè)到__declaredMethods
  • 如果f為nil,則去父類取該字段
  • 將域添加到子類中

5. _propagateInstanceMethod(aClass, name, f)

添加域到表中,并添加到所有的子類中,相當(dāng)于繼承

local function _propagateInstanceMethod(aClass, name, f)
  f = name == "__index" and _createIndexWrapper(aClass, f) or f
  aClass.__instanceDict[name] = f

  for subclass in pairs(aClass.subclasses) do
    if rawget(subclass.__declaredMethods, name) == nil then
      _propagateInstanceMethod(subclass, name, f)
    end
  end
end
  • 如果name = __index, 調(diào)用_createIndexWrapper
  • 將f添加到aClass.__instanceDict[name]中
  • 遍歷所有子類,如果子類不包含該方法,則添加到子類中(若包含,相當(dāng)于重寫)

6. _createIndexWrapper(aClass, f)

對(duì)__index處理

local function _createIndexWrapper(aClass, f)
  if f == nil then
    return aClass.__instanceDict
  else
    return function(self, name)
      local value = aClass.__instanceDict[name]

      if value ~= nil then
        return value
      elseif type(f) == "function" then
        return (f(self, name))
      else
        return f[name]
      end
    end
  end
end
  • f為空,則返回aClass.__instanceDict
  • 如果__instanceDict包含name 則返回 <==> __index = __instanceDict
  • 如果f為函數(shù), __index = f(self,name)
  • 否則,返回f[name]

7. _call(self, ...)

調(diào)用new方法,使A:new() <==> A()

8. _tostring(self)

** 默認(rèn)tostring方法**

9. middleclass.class(name, super)

創(chuàng)建一個(gè)類,并設(shè)置父類

  • 如果super ~= nil 則調(diào)用subclass, 將那么添加到super的子類中
  • 否則,創(chuàng)建一張默認(rèn)表,并將DefaultMixin合并進(jìn)去

實(shí)例解析

Metamethods

不需設(shè)置metatable的元方法,直接在當(dāng)前類中定義,即可實(shí)現(xiàn)原方法。
以tostring為例:

Point = class('Point')
function Point:initialize(x,y)
  self.x = x
  self.y = y
end
function Point:__tostring()
  return 'Point: [' .. tostring(self.x) .. ', ' .. tostring(self.y) .. ']'
end

p1 = Point(100, 200)
p2 = Point(35, -10)
print(p1)
print(p2)

Output:
Point: [100, 200]
Point: [35, -10]

  1. p1(實(shí)例)的__index為__instanceDict,所以調(diào)用tostring時(shí),會(huì)去__instanceDict中去查找
  2. Pointer的__newindex為_declareInstanceMethod,在類中定義__tostring時(shí),_declareInstanceMethod會(huì)將該方法加入到__instanceDict中
  3. 重寫__tostring,相當(dāng)于在自己的元表中定義該方法
  4. 其他元方法類似

Middleclass 4.x supports all the Lua metamethods. There are some restrictions:

  • Overriding the metatable metamethod is possible, but likely will give you trouble. Do this only if you know what you are doing.
  • Metamethods not supported by the Lua version being used are not supported. For example, the len metamethod does not work in Lua 5.1 or LuaJIT without 5.2 compatibility.

mixins

類變量提供include方法,可以將一個(gè)table的域拷貝到另一個(gè)table中,被拷貝的table會(huì)觸發(fā)included方法

  1. class.static表中提供include方法
  2. class的__index指向class.static
  3. 被合并的table 調(diào)用include方法

Private stuff

在類內(nèi)定義局部變量,或者局部函數(shù),外部不可訪問

lua的作用于限制

其他

class = require("middleclass")
A = class("A")
A.n = 1
B = A()
print(B.n)
B.n = 2
print(B.n)
print(A.n)

Output:
1
2
1

B是A的實(shí)例,B繼承了n(B中沒有n屬性,則去__instanceDict中取)
當(dāng)B對(duì)n賦值,則相當(dāng)于在B表中添加屬性,不會(huì)改變__instanceDict的值,再次獲取該屬性時(shí),直接從B表中讀,所以值為2,且不會(huì)改變A中的值

middleclass使用的表的簡單總結(jié)

  1. __instanceDict 記錄當(dāng)前類,以及所有父類定義的實(shí)例方法(屬性), __index指向自己
  2. __declaredMethods 記錄當(dāng)前類聲明的方法(屬性)
  3. subclasses 當(dāng)前類的所有子類,弱引用
  4. static 靜態(tài)表,定義new, include, isSubclassOf等方法,__index指向__instanceDict。
    實(shí)例變量不能直接訪問static表,必須通過.class.static訪問
    類的靜態(tài)方法可以通過class.static:func 來定義
  5. 類的默認(rèn)表 定義__instanceDict,__declaredMethods, static等屬性。
    __index指向static表,可以直接使用static中的字段(A:new())。
    __newIndex為_declareInstanceMethod方法,添加字段時(shí)會(huì)更新__instanceDict以及__declareMethods
  6. 實(shí)例表 定義class屬性,指向當(dāng)前的類。 metatable為對(duì)應(yīng)類的__instanceDict
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評(píng)論 19 139
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,041評(píng)論 0 9
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,637評(píng)論 18 399
  • 對(duì)象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法,而不是構(gòu)造函數(shù)創(chuàng)建對(duì)象:僅僅是創(chuàng)建對(duì)象的方法,并非Fa...
    孫小磊閱讀 2,182評(píng)論 0 3
  • 「禪繞」春天+商陸根和商陸葉+米爾的嘗試,用了暗線250,中間的小塊弄的很糟糕,不過也不想涂黑,就那樣吧,回頭再試...
    五一的簡書閱讀 1,651評(píng)論 0 0

友情鏈接更多精彩內(nèi)容