《Programming in Lua 3》讀書筆記(十二)

日期:2014.7.14 ? ??

PartⅡ Object-Oriented Programming

Lua中實現面向對象編程。
“如同OOP對象,table擁有狀態;如同OOP對象,table擁有標識符---self,用來與其他變量做區分,而且兩個table擁有同樣的值也是不同的object(對象),因為self的不同;如同OOP對象,table也有生命周期,這個生命周期與誰在何處創建table是保持獨立的”

對象是擁有自己的運算操作的,table也有,如
e.g.
Account = {blanche = 0}
function Account.withdraw(v)Account.balance = Account.balance - v
end
上述的函數就是OOP中稱呼的method(方法)。當然,上述的使用技巧是不可取的:在函數體內使用全局變量Account。這樣會造成嚴重的后果,而且這樣使用限制性太大,當我們改變了變量類型,這個操作就失效了。這種操作與面向對象編程中對象保持獨立的生存周期這一原則相悖。
e.g.
a , Account = Account,nil
a.withdraw(100.00)          --error
因為我們將Account賦值為nil了,所以withdraw函數就會報錯。

針對上述的操作改進:我們可以傳遞額外的參數,作為函數運算的對象
e.g.
function Account.withdraw(self,v)self.balance = self.balance - v
end
此時
a , Account = Account,nil
a.withdraw(100.00)          --ok

但是在大多數面向對象編程的語言中,一般都是隱藏我們上述用到的那個參數。Lua也能隱藏這個參數,這里就要使用到冒號操作符
e.g.
function Account:withdraw(v)self.balance = self.balance - v
end
當然,這里使用冒號操作符只是一個語法約定而已,沒有額外的意思。我們可以用點號運算符定義一個函數然后用冒號運算符調用該函數,反之亦然
e.g.
Account = {balance = 0,withdraw = function (self,v)self.balance = self.balance - vend}
function Account:deposit (v)self.balance = self.balance + v
end
Account.deposit(Account,200)

我個人還是覺得按套路來,遵循這種語法約定。


16.1 Classes
Lua中沒有類(class)的概念,但是很容易模仿出類。參考了prototype-base language(面向原型編程)中prototype(原型)的相關技巧。在這種語言中,也是沒有類,但是每個對象都擁有一個原型。在這種語言環境下要表現出類的概念,我們只需要為繼承者創建一個唯一的對象作為原型。類和原型的目的都在于共享某些行為。

前面在討論元表的時候有提到繼承,因此假如現在有兩個對象a和b,采用如下操作便可將b設置為a的原型:
e.g.
setmetatable(a,{__index = b})
執行了這個操作之后,假如我們訪問a中的成員,在找不到的時候會訪問b。

回到現在討論的類,假如我們需要創建一個新的account,其行為與Account一樣,在這里我們就可以考慮使用繼承,使用 __index 元方法。在這里我們不需要額外創建一個新的table作為元表,可以直接將我們要繼承的table設置為其元表:
e.g.
function Account:new(o)o = o or {}setmetatable(o,self)self.__index = selfreturn o
end
這里使用到了前文提到的冒號操作符,默認使用了self參數。
此時
a = Account:new(balance = 0}
a:deposit(100.00)
我們新建了一個table ?a,其元表為Account,又修改了其元方法__index 為Account 自身,當我們在a中尋找deposit的時候,找不到的時候會自動在Account中尋找,達到了繼承的要求。
創建a的時候,將balance賦值為了0,假如不給其賦值,則會繼承其默認值
b = Account:new()
print(b.balance)               --- 0     繼承了Account的balance的值0


16.2 Inheritance
繼承
Lua中實現繼承還是比較容易的
e.g.
--基類
Account = {balance = 0 }
function Account:new(o)o = o or {}setmetatable(0,self)self.__index = selfreturn o
end
function Account:deposit(v)self.balance = self.balance + v
end
function Account:withdraw(v)if v > self.balance then error "xxx" endself.balance = self.balance - v
end

現在我們想寫一個子類繼承這個基類,然后能在子類中做進一步的修改,可以這樣操作
SpecialAccount = Account:new()
執行以上操作之后,SpecialAccount 便是Account的一個實例了(--modify 應該是繼承而非實例吧?),當我們執行一下操作:
s = SpecialAccount:new(limit = 1000.00}
SpecialAccount 從基類中繼承了new這個方法,因為這里使用了冒號操作符,默認使用了SpecialAccount這個參數,因此此時s的元表是SpecialAccount。當我們試圖訪問s中不存在的元素的時候,便會去SpecialAccount中尋找,而從SpecialAccount中尋找不到的時,轉而會去Account中尋找。
e.g.
s:deposit(100.00)
此時lua會在s、SpecialAccount、Account里面尋找deposit方法

我們可以在子類中重新定義從基類中繼承的方法:
e.g.
function SpecialAccount:withdraw(v)if v - self.balance >= self.getLimit() thenerror"xx"endself.balance = self.balance - v
end
function SpecialAccount:getLimit()return self.limit or 0
end

此時,當我們調用s:withdraw的時候,lua會直接在SpecialAccount找到該方法,執行該方法內的操作。
而lua中有趣的一點是,不需要重新創建一個新的類來實現一個新的行為,可以直接在對象中實現該行為,如:
上文我們已經創建了SpecialAccount對象s,我們要在s中實現一個限制行為,限制每次的操作限額,我們可以這樣實現:
e.g.
function s:getLimit()return self.balance * 0.10
end
這樣,當我們調用s:withdraw的時候,條件判斷getLimit會直接得到s已經定義的行為,而不會再去SpecialAccount中尋找。


16.3 Multiple Inheritance
多重繼承

Lua中實現面向對象編程是有很多種途徑的,上文中提到的使用 __index 元方法是一種便捷的方式。在不同的情況下需要選擇不同的實現方式,在這里介紹的是一種能實現多重繼承的方法。
這里也涉及到了使用__index 元方法,在該方法內使用一個函數。當table的元表的 __index 字段中有一個函數的時候,Lua都會調用該函數而不管有沒有在該table中尋找到key。
多重繼承的思想在于一個類可以有多個父類。因此我們就不能用類的方法來創建子類,而是定義一個函數來實現該功能--createClass,以父類作為參數來創建子類。這個函數創建一個table來代表新的類,然后設置元表的元方法__index 來實現多重繼承。在這里有要注意的地方,類和父類的關系與類和實例的關系是有差異的,一個類不能同時成為其實例和其子類的元表
e.g.
--假定現在有兩個類,之前的Account和現在的Named
Named = {}
function Named:getname()return self.name
end
function Named:setname(v)self.name = v
end--在plist這個table中尋找k
local function search(k,plist)for i = 1,#plist dolocal v = plist[i][k]if v then return v endend
endfunction createClass(…)local c = {}               --新的類local parents = { … }--從父類table中找到各個父類中的方法setmetatable(c,{ __index = function (t,k)return search(k,parents)end} )     --多重繼承的技巧在于此處,__index 元方法是一個函數,該函數會從父類列表中尋找每個父類中的所有方法,這樣就實現了多重繼承--新的類成為其實例的元表c.__index = c--創建新的類的構造方法function c:new(o)o = o or {}setmetatable(o,c)return oendreturn c
end

現在我們就能創建一個多重繼承的類了:
--多重繼承,創建新的類
NamedAccount = createClass(Account,Named)

--創建和使用實例
account = NamedAccount:new{name = "abcd"}
print(account:getname())

上述的search函數一定程度上影響性能,以下是作者給的改進:
setmetatable(c,{ __index = function ( t,k )local  v = search(k,parents)t[k] = vreturn vend})

一種編程技巧,謹記!

16.4 Privacy
隱私

在已提到的對對象的設計中,并沒有提供隱私機制。這是我們使用table來表現對象的結果,也是受影響與Lua本身排斥一些冗余、人為限制的功能。作者的建議是假如不想訪問某些值,那么大可以不去訪問就是。
Lua的目標是為開發者提供便利,提供多種技巧實現多數需求,盡管設計lua中的對象初衷是不提供隱私機制的,但是可以通過別的方法來實現這個需求——訪問控制。這個用的比較少,但還是值得去了解和學習掌握的。
實現這個功能需求在于用兩個table來表現對象:一個表示其狀態,一個用來表示其操作行為。訪問對象的時候通過第二個table進行訪問,而對第一個table的設計也有一定的要求,該table并不是存儲在別的table中,而是存儲在該對象方法的closure中。以此重新設計Account
e.g.
function newAccount( initialBalance )local self = {balance = initialBalance}local withdraw = function ( v )self.balance = self.balance + vendlocal getBalance = function ( ... )return self.balanceendreturn{withdraw = withdraw,deposit = deposit,getBalance = getBalance}
end

在這里該函數首先創建了一個table用來存儲內部對象的狀態,存儲至一個局部變量self。然后該函數內部創建了對象的一系列方法。最后函數創建并返回了另外一個對象,該對象內部存儲了實際上要實現的方法的名字。返回的這個新的table應該相當于上文提到的第二個table。這里的核心點在于:這些方法沒有使用冒號操作符得到self這個額外的默認參數,而是直接使用了。現在我們可以以一下方式創建新的對象并使用其方法:
e.g.
acc1 = newAccount(100.00)
acc1.withdraw(40.00)
print(acc1.getBalance())

利用這種方式創建的table,我們是沒有辦法直接訪問原table的,只能通過newAccount里面的方法來訪問。這樣就實現來我們想要的隱私功能。


16.5 The Single-Method Approach
單例的實現

e.g.
print("The Single-Method Approach \n") 
function newObject( value )return function ( action,v )if action == "get" then return valueelseif action == "set" then value = velse error("invalid action")endend
endd = newObject(0)
print(d("get"))
d("set",10)
print(d("get"))


沒有實例,直接通過對象本身訪問對象實現的方法。

?

轉載于:https://www.cnblogs.com/zhong-dev/p/4044574.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274814.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274814.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274814.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(轉)AS3中的stage,this,root的區別

要了解這個問題就要先對flash中的顯示對象結構有一個大概的了解: 第一級:舞臺; 第二級:當前SWF; 第三級:各種容器及可視對象(如:文本框,位圖……)&#xff1b…

面試官是怎樣高效面試的(面試官的“套路”

大家好,我是若川。持續組織了6個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列最近正…

微服務負載均衡實現高可用_使用負載平衡實現大容量可用性

微服務負載均衡實現高可用Written by Yona Gidalevitz由Yona Gidalevitz撰寫 Most users of the web are blissfully unaware of the sheer scale of the process responsible for bringing content across the Internet. There are literally miles of Internet between you …

Visual Studio 2008自帶的Windows 系統使用的各種圖標、光標和動畫文件

1,Visual Studio 2008自帶的1000多個 Windows 系統使用的各種圖標、光標和動畫文件 在Visual Studio 2008的安裝目錄下, /Microsoft Visual Studio 9.0/Common7/VS2008ImageLibrary/2052文件夾下面,有一個VS2008ImageLibrary.zip,…

Android中導入第三方jar

右鍵工程,Build path,Java build path,選擇libraries在右邊的按鈕中點擊“Add Library”選擇“User library”,點擊“下一步”點擊“User librarys”按鈕在出現的界面中點擊“New..”按鈕在彈出的界面中隨便起一個名字,點擊“確定”點擊“Add jars”按鈕…

19歲中專學歷是怎么在廣州找到前端工作的?

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列本文來…

tcp 接收端優雅的寫法_如何更優雅地接收設計反饋

tcp 接收端優雅的寫法重點 (Top highlight)It’s rare to meet a designer that doesn’t take pride in their work. After all, we are creatives and it’s what we love to do. Although design is teachable, there is a bit of natural skill and talent that comes into…

C++頭文件一覽表

傳統 C   #include <assert.h>    //設定插入點   #include <ctype.h>//字符處理   #include <errno.h>//定義錯誤碼   #include <float.h>//浮點數處理   #include <fstream.h>//文件輸入&#xff0f;輸出   #include &l…

一份 2.5k star 的《React 開發思想綱領》

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列翻譯自…

asp.net生成jason給js

[WebMethod(EnableSession true)][ScriptMethod]public static object TEST(string testval){int type 0;string message "";int precent 0;return new { type type, message message, precent precent };} 轉載于:https://www.cnblogs.com/bulege/archive/20…

文案寫作軟件_11種可改善網站用戶體驗的文案寫作技術

文案寫作軟件Written by John Stevens約翰史蒂文斯 ( John Stevens)撰寫 When we talk about user experience and your website, it is easy to get caught up in the site’s design and navigation options. While that is important, the words you place on the page are…

Table.Rows.Remove(dr)和Table.Delete()的區別

一個DataRow對象剛被創建之后其狀態是Detached&#xff0c;是孤立的一個存在&#xff0c;所以建立了DataRow之后在DataRow中的單元填充了數據后還要通過DataTable.Rows.Add(DataRow)方法將此DataRow添加到DataTable&#xff0c;DataRow添加到DataTable后, 這個DataRow的狀態就…

張小龍談用戶體驗

原文&#xff1a;http://sd.csdn.net/a/20120510/2805483.html從Foxmail到騰訊“七星級產品”QQ郵箱&#xff0c;再到騰訊核武器級產品微信。在外界看來&#xff0c;騰訊副總裁、廣州研發部總經理張小龍作風低調&#xff0c;很少接受正式的媒體采訪。然而作為當今國內最優秀的產…

如何高效學習前端新知識,我推薦這些~

眾所周知&#xff0c;關注公眾號可以了解學習掌握技術方向&#xff0c;學習優質好文&#xff0c;落實到自己項目中。還可以結交圈內好友&#xff0c;讓自己融入到積極上進的技術氛圍&#xff0c;促進自己的技術提升。話不多說&#xff0c;推薦這些優質前端公眾號前端之神100w閱…

web開發集成數字證書_每個數字設計師都應該知道的Web開發的七個原則

web開發集成數字證書A career path into digital design is often winding, meaning many practitioners come from adjacent fields as diverse as graphic design, web development, research, or even anthropology. As a result, two people working in a similar role may…

【轉】CentOS 6.6 升級GCC G++ (當前最新版本為v6.1.0) (完整)

原文地址&#xff1a;https://www.cnblogs.com/lzpong/p/5755678.html 我這里是centos7 升級到gcc8.1&#xff0c;過程差不多&#xff0c;參考這篇文章&#xff0c;記錄一下。 ---原文--- CentOS 6.6 升級GCC G (當前最新GCC/G版本為v6.1.0) 沒有便捷方式, yum update.... yu…

Hadoop:mapreduce的splitsize和blocksize

參考&#xff1a; Hadoop MapReduce中如何處理跨行Block和UnputSplit https://stackoverflow.com/questions/17727468/hadoop-input-split-size-vs-block-size https://stackoverflow.com/questions/30549261/split-size-vs-block-size-in-hadoop轉載于:https://www.cnblogs.co…

前端工程師生產環境 debugger 技巧

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列導言開…

bmp轉jpg(使用libjpeg)

jpg壓縮原理可以參考這篇文章http://hi.baidu.com/tiandsp/item/f5a2dcde6ef1405bd73aae41&#xff0c;我很早以前轉的一篇文章。 沒有使用libjpeg的壓縮代碼可以看看這篇文章http://hi.baidu.com/tiandsp/item/9b5843c58a3b4474cfd4f841&#xff0c;也是我很早以前轉的。 這次…

figma設計_Figma與Adobe XD:我們如何選擇下一個設計工具

figma設計The time came for changes and our design team started raising the topic again about how we should consider moving away from Sketch. This is not the first time this question came to mind, but this time seems like it was serious. Last summer we cons…