Mathematica 面向?qū)ο缶幊探鉀Q方案
瀏覽:128857
面向?qū)ο笤?
什么是面向?qū)ο螅烤S基百科說(shuō),“面向?qū)ο蟪绦蛟O(shè)計(jì)(英語(yǔ):Object-oriented programming,縮寫:OOP),指一種程序設(shè)計(jì)范型,同時(shí)也是一種程序開(kāi)發(fā)的方法。它將對(duì)象作為程序的基本單元,將程序和數(shù)據(jù)封裝其中,以提高軟件的重用性、靈活性和擴(kuò)展性”。
C語(yǔ)言是面向過(guò)程的,我們把要做的事情分成一個(gè)個(gè)函數(shù)來(lái)完成,比如我要寫一個(gè)公交車自動(dòng)收費(fèi)系統(tǒng),那么我需要為公交車行駛,公交車報(bào)站,公交車開(kāi)關(guān)門,乘客上車,乘客交費(fèi),乘客刷卡等行為編寫相應(yīng)的函數(shù)。
后來(lái)人們發(fā)現(xiàn),程序里的很多函數(shù)有很強(qiáng)的分類性與隔離性,公交車行駛可能和乘客上車完全不相干;而且人類認(rèn)知世界的方式也是先知道有某樣?xùn)|西,然后知道它有什么用。因此,一種面向?qū)ο蟮某绦蛟O(shè)計(jì)思想逐漸誕生。
面向?qū)ο罄镒詈诵牡母拍罹褪穷惡蛯?duì)象。拿生物作類比,類就是一種物種,對(duì)象就是一個(gè)特定的生物;類是抽象的概念,對(duì)象是存在的實(shí)體。因此,對(duì)于“貓”這個(gè)類,它有性別,毛色,年齡等數(shù)據(jù)屬性(稱為成員變量),還有捉老鼠,睡覺(jué)等行為屬性(稱為成員函數(shù));而一只特定的貓,就會(huì)擁有它自己特定的性別,毛色和年齡,但對(duì)于成員函數(shù),相同類的對(duì)象是相同的,只是函數(shù)執(zhí)行時(shí)會(huì)用到對(duì)象的成員變量值而計(jì)算出不同的結(jié)果。
類概念的引入,使得我們可以把相關(guān)性很強(qiáng)的函數(shù)與數(shù)據(jù)進(jìn)行封裝,增強(qiáng)程序的模塊化程度;同時(shí)面向?qū)ο蟾舆m宜我們對(duì)一個(gè)大型項(xiàng)目進(jìn)行建模。
那么,C++里的面向?qū)ο笫鞘裁礃幼拥哪兀课覀儊?lái)看個(gè)例子。
假設(shè)我們有兩個(gè)學(xué)生對(duì)象 tom和kate,他們都有speak函數(shù)來(lái)說(shuō)出自己的名字,
tom.speak();
kate.speak();
運(yùn)行結(jié)果可能是
My name is Tom.
My name is Kate.
我們看到,兩個(gè)speak函數(shù)具有相同的 簽名(signature,表示這個(gè)函數(shù)的參數(shù)類型,數(shù)目,返回值類型等一系列特征),但執(zhí)行時(shí)帶入了不同的參數(shù)。實(shí)際上,C++的成員函數(shù)與普通函數(shù)有 個(gè)本質(zhì)區(qū)別,即成員函數(shù)有一個(gè)隱含參數(shù)this,表示調(diào)用該成員函數(shù)的對(duì)象的指針,這樣,成員函數(shù)就能夠通過(guò)this訪問(wèn)這個(gè)對(duì)象的成員變量與函數(shù),從而 根據(jù)不同的對(duì)象算出不同的結(jié)果。這就是C++面向?qū)ο蠹夹g(shù)中最關(guān)鍵的地方,this指針的引入,實(shí)際上,在其他面向?qū)ο笳Z(yǔ)言中都有相似的機(jī)制。
Mathematica 面向?qū)ο蟮膶?shí)現(xiàn)
那么,我們?cè)撊绾卧贛athematica模擬出面向?qū)ο蟮男Ч兀?
首先看類的結(jié)構(gòu)是什么樣子的。
類,其實(shí)就是一組成員變量和成員函數(shù)的列表。假設(shè)我們有一個(gè) man 類,包含 name 變量和 say 函數(shù)。那么,我們可以把man定義成如下的形式
{{“name”, Null},{"say",Null}}
我們無(wú)需區(qū)分變量和函數(shù)(它們統(tǒng)稱為域),直接把它們放在同一個(gè)List里。每一個(gè)域都對(duì)應(yīng)一個(gè)二元List,分別表示它的名字和值;這么做是為了方便我們?cè)L問(wèn)這個(gè)域。
這里需要額外插點(diǎn)其他技術(shù)知識(shí)。面向?qū)ο蟮念惱镉幸环N特殊的函數(shù)與變量,稱為靜態(tài)函數(shù)與靜態(tài)變量。這些變量是不屬于任何對(duì)象而是屬于這個(gè)類 的,并且被所有對(duì)象所共享。比如“貓”類,我們有一個(gè)靜態(tài)變量maxAge,表示貓的最大壽命,比如我們?nèi)?0,那么所有的貓對(duì)象都可以訪問(wèn)這個(gè)數(shù)據(jù)甚至 修改它,但這個(gè)數(shù)據(jù)不屬于任何貓對(duì)象,而是貓類的一個(gè)公共屬性。
我們的Mathematica實(shí)現(xiàn)里,沒(méi)有明顯的區(qū)分靜 態(tài)函數(shù)、靜態(tài)變量;事實(shí)上,我們的對(duì)象具有和類一模一樣的結(jié)構(gòu),通過(guò)類訪問(wèn)域,得到的就是靜態(tài)域,通過(guò)對(duì)象訪問(wèn),得到的就是成員域。我們的這種實(shí)現(xiàn)有如下 的局限:對(duì)象中也保存著靜態(tài)域的數(shù)據(jù);對(duì)象可以修改靜態(tài)域但是不會(huì)更新類的靜態(tài)域(這個(gè)缺陷可以通過(guò)小修改來(lái)克服,暫時(shí)沒(méi)有實(shí)現(xiàn))
正如上面所說(shuō),我們的對(duì)象具有和類完全相同的結(jié)構(gòu),因此從一個(gè)類構(gòu)建一個(gè)對(duì)象只需要復(fù)制這個(gè)類的結(jié)構(gòu)即可。
接下來(lái)的一個(gè)問(wèn)題便是,我們?cè)撊绾卧L問(wèn)這個(gè)類的域呢?
我們?cè)谇懊娴睦夼_(tái)帖子( http://forum.caenet.com/thread-997834-1-1.html)中給出了如下的訪問(wèn)方法:
tom = New[man];
tom["year"] = 1989;
tom["name"] = "tom";
tom["say"][]
tom["age"][]
相當(dāng)于用一個(gè)下標(biāo)作為索引訪問(wèn)具體的值。FlyingDuckman 通過(guò)定義New來(lái)實(shí)現(xiàn),我當(dāng)時(shí)已經(jīng)指出其中的問(wèn)題;而且還有一個(gè)更深入的問(wèn)題在于,如此實(shí)現(xiàn),New將不堪重負(fù),每定義一個(gè)類就要定義這么一組New函數(shù),完全不符合我們的需求。
對(duì)于前一個(gè)問(wèn)題,我們就要仿造C++來(lái)引入this指針,這個(gè)會(huì)在后面介紹;后一個(gè)問(wèn)題,我們要使用一種特殊的機(jī)制,稱為 Dynamic Dispatch(參見(jiàn) http://en.wikipedia.org/wiki/Dynamic_dispatch)。
不知道大家是否還記得或者閱讀過(guò)這篇文章 http://forum.caenet.com/viewthread.php?tid=991845&highlight=%B1%D5%B0%FC,關(guān)于Mathematica中的閉包實(shí)現(xiàn)。我們這里不需要使用閉包,但是它給我們提供了一種無(wú)與倫比的技術(shù):匿名變量。
匿名變量?Ok,這是我自己杜撰的名詞,但它名副其實(shí)。那個(gè)例子里,你知道y是什么么?不,你永遠(yuǎn)不知道,除非你用?去搜索所有以y開(kāi)頭的變量;但是y卻是客觀存在的,并且每當(dāng)你調(diào)用Add函數(shù)時(shí),不僅改變了y的值而且返回它。這就是匿名變量的全部?jī)?nèi)涵。
那么匿名變量對(duì)我們有什么幫助呢?它就是我們實(shí)現(xiàn)Dynamic Dispatch的核心。
我來(lái)舉一個(gè)簡(jiǎn)單的例子。
lily = Module[{me},
me["name"] = "Lily";
me["say"] := Function[{}, Print["My name is ", me["name"]]];
me
]
lily["say"][]
OK,把這段代碼仔細(xì)品味品味,我的面向?qū)ο笏枷胍呀?jīng)昭然若揭。
我不想過(guò)多解釋這段代碼,只希望你好好考慮如下的問(wèn)題:lily是什么?lily[“say”][] 是怎么執(zhí)行的?
這個(gè)解決方案的誕生不是靈光一現(xiàn),它足足折磨了我三天三夜;感謝《計(jì)算機(jī)程序的構(gòu)造與解釋》,這個(gè)解決方案幾乎完全是由它給出的。
this指針的實(shí)現(xiàn)
那么this指針呢?你肯定立馬可以看出來(lái),上面的me就是this指針。對(duì)于類的域函數(shù)定義,包含兩種類型:第一種是靜態(tài)函數(shù),定義成 Function[{x},y],y僅僅是x的函數(shù),與對(duì)象無(wú)關(guān);第二種是成員函數(shù),定義成 Function[{this},Function[{x},y]],y是this和x的函數(shù),this代表傳入的對(duì)象。在對(duì)象中dispatch函數(shù) 時(shí),根據(jù)嵌套的Function層數(shù)決定是否是靜態(tài)函數(shù)。至此,我們的面向?qū)ο篌w系基本架構(gòu)完成。
以下是使用我編寫的程序包實(shí)現(xiàn)的小程序。
<< DabaoClass`
man = DefClass["man", {year, name}]
AddField[man, "age"]
man["age"] =
Function[{this}, Function[{}, First[DateList[]] - this["year"] + 1]];
AddField[man, "say"]
man["say"] =
Function[{this}, Print["My name is ", this["name"], "\nI'm ",
this["age"][], " year's old"] &];
tom = New[man];
tom["year"] = 1989;
tom["name"] = "tom";
tom["say"][]
tom["age"][]
運(yùn)行結(jié)果
My name is tom
I'm 23 year's old
程序包下載
什么是面向?qū)ο螅烤S基百科說(shuō),“面向?qū)ο蟪绦蛟O(shè)計(jì)(英語(yǔ):Object-oriented programming,縮寫:OOP),指一種程序設(shè)計(jì)范型,同時(shí)也是一種程序開(kāi)發(fā)的方法。它將對(duì)象作為程序的基本單元,將程序和數(shù)據(jù)封裝其中,以提高軟件的重用性、靈活性和擴(kuò)展性”。
C語(yǔ)言是面向過(guò)程的,我們把要做的事情分成一個(gè)個(gè)函數(shù)來(lái)完成,比如我要寫一個(gè)公交車自動(dòng)收費(fèi)系統(tǒng),那么我需要為公交車行駛,公交車報(bào)站,公交車開(kāi)關(guān)門,乘客上車,乘客交費(fèi),乘客刷卡等行為編寫相應(yīng)的函數(shù)。
后來(lái)人們發(fā)現(xiàn),程序里的很多函數(shù)有很強(qiáng)的分類性與隔離性,公交車行駛可能和乘客上車完全不相干;而且人類認(rèn)知世界的方式也是先知道有某樣?xùn)|西,然后知道它有什么用。因此,一種面向?qū)ο蟮某绦蛟O(shè)計(jì)思想逐漸誕生。
面向?qū)ο罄镒詈诵牡母拍罹褪穷惡蛯?duì)象。拿生物作類比,類就是一種物種,對(duì)象就是一個(gè)特定的生物;類是抽象的概念,對(duì)象是存在的實(shí)體。因此,對(duì)于“貓”這個(gè)類,它有性別,毛色,年齡等數(shù)據(jù)屬性(稱為成員變量),還有捉老鼠,睡覺(jué)等行為屬性(稱為成員函數(shù));而一只特定的貓,就會(huì)擁有它自己特定的性別,毛色和年齡,但對(duì)于成員函數(shù),相同類的對(duì)象是相同的,只是函數(shù)執(zhí)行時(shí)會(huì)用到對(duì)象的成員變量值而計(jì)算出不同的結(jié)果。
類概念的引入,使得我們可以把相關(guān)性很強(qiáng)的函數(shù)與數(shù)據(jù)進(jìn)行封裝,增強(qiáng)程序的模塊化程度;同時(shí)面向?qū)ο蟾舆m宜我們對(duì)一個(gè)大型項(xiàng)目進(jìn)行建模。
那么,C++里的面向?qū)ο笫鞘裁礃幼拥哪兀课覀儊?lái)看個(gè)例子。
假設(shè)我們有兩個(gè)學(xué)生對(duì)象 tom和kate,他們都有speak函數(shù)來(lái)說(shuō)出自己的名字,
tom.speak();
kate.speak();
運(yùn)行結(jié)果可能是
My name is Tom.
My name is Kate.
我們看到,兩個(gè)speak函數(shù)具有相同的 簽名(signature,表示這個(gè)函數(shù)的參數(shù)類型,數(shù)目,返回值類型等一系列特征),但執(zhí)行時(shí)帶入了不同的參數(shù)。實(shí)際上,C++的成員函數(shù)與普通函數(shù)有 個(gè)本質(zhì)區(qū)別,即成員函數(shù)有一個(gè)隱含參數(shù)this,表示調(diào)用該成員函數(shù)的對(duì)象的指針,這樣,成員函數(shù)就能夠通過(guò)this訪問(wèn)這個(gè)對(duì)象的成員變量與函數(shù),從而 根據(jù)不同的對(duì)象算出不同的結(jié)果。這就是C++面向?qū)ο蠹夹g(shù)中最關(guān)鍵的地方,this指針的引入,實(shí)際上,在其他面向?qū)ο笳Z(yǔ)言中都有相似的機(jī)制。
Mathematica 面向?qū)ο蟮膶?shí)現(xiàn)
那么,我們?cè)撊绾卧贛athematica模擬出面向?qū)ο蟮男Ч兀?
首先看類的結(jié)構(gòu)是什么樣子的。
類,其實(shí)就是一組成員變量和成員函數(shù)的列表。假設(shè)我們有一個(gè) man 類,包含 name 變量和 say 函數(shù)。那么,我們可以把man定義成如下的形式
{{“name”, Null},{"say",Null}}
我們無(wú)需區(qū)分變量和函數(shù)(它們統(tǒng)稱為域),直接把它們放在同一個(gè)List里。每一個(gè)域都對(duì)應(yīng)一個(gè)二元List,分別表示它的名字和值;這么做是為了方便我們?cè)L問(wèn)這個(gè)域。
這里需要額外插點(diǎn)其他技術(shù)知識(shí)。面向?qū)ο蟮念惱镉幸环N特殊的函數(shù)與變量,稱為靜態(tài)函數(shù)與靜態(tài)變量。這些變量是不屬于任何對(duì)象而是屬于這個(gè)類 的,并且被所有對(duì)象所共享。比如“貓”類,我們有一個(gè)靜態(tài)變量maxAge,表示貓的最大壽命,比如我們?nèi)?0,那么所有的貓對(duì)象都可以訪問(wèn)這個(gè)數(shù)據(jù)甚至 修改它,但這個(gè)數(shù)據(jù)不屬于任何貓對(duì)象,而是貓類的一個(gè)公共屬性。
我們的Mathematica實(shí)現(xiàn)里,沒(méi)有明顯的區(qū)分靜 態(tài)函數(shù)、靜態(tài)變量;事實(shí)上,我們的對(duì)象具有和類一模一樣的結(jié)構(gòu),通過(guò)類訪問(wèn)域,得到的就是靜態(tài)域,通過(guò)對(duì)象訪問(wèn),得到的就是成員域。我們的這種實(shí)現(xiàn)有如下 的局限:對(duì)象中也保存著靜態(tài)域的數(shù)據(jù);對(duì)象可以修改靜態(tài)域但是不會(huì)更新類的靜態(tài)域(這個(gè)缺陷可以通過(guò)小修改來(lái)克服,暫時(shí)沒(méi)有實(shí)現(xiàn))
正如上面所說(shuō),我們的對(duì)象具有和類完全相同的結(jié)構(gòu),因此從一個(gè)類構(gòu)建一個(gè)對(duì)象只需要復(fù)制這個(gè)類的結(jié)構(gòu)即可。
接下來(lái)的一個(gè)問(wèn)題便是,我們?cè)撊绾卧L問(wèn)這個(gè)類的域呢?
我們?cè)谇懊娴睦夼_(tái)帖子( http://forum.caenet.com/thread-997834-1-1.html)中給出了如下的訪問(wèn)方法:
tom = New[man];
tom["year"] = 1989;
tom["name"] = "tom";
tom["say"][]
tom["age"][]
相當(dāng)于用一個(gè)下標(biāo)作為索引訪問(wèn)具體的值。FlyingDuckman 通過(guò)定義New來(lái)實(shí)現(xiàn),我當(dāng)時(shí)已經(jīng)指出其中的問(wèn)題;而且還有一個(gè)更深入的問(wèn)題在于,如此實(shí)現(xiàn),New將不堪重負(fù),每定義一個(gè)類就要定義這么一組New函數(shù),完全不符合我們的需求。
對(duì)于前一個(gè)問(wèn)題,我們就要仿造C++來(lái)引入this指針,這個(gè)會(huì)在后面介紹;后一個(gè)問(wèn)題,我們要使用一種特殊的機(jī)制,稱為 Dynamic Dispatch(參見(jiàn) http://en.wikipedia.org/wiki/Dynamic_dispatch)。
不知道大家是否還記得或者閱讀過(guò)這篇文章 http://forum.caenet.com/viewthread.php?tid=991845&highlight=%B1%D5%B0%FC,關(guān)于Mathematica中的閉包實(shí)現(xiàn)。我們這里不需要使用閉包,但是它給我們提供了一種無(wú)與倫比的技術(shù):匿名變量。
匿名變量?Ok,這是我自己杜撰的名詞,但它名副其實(shí)。那個(gè)例子里,你知道y是什么么?不,你永遠(yuǎn)不知道,除非你用?去搜索所有以y開(kāi)頭的變量;但是y卻是客觀存在的,并且每當(dāng)你調(diào)用Add函數(shù)時(shí),不僅改變了y的值而且返回它。這就是匿名變量的全部?jī)?nèi)涵。
那么匿名變量對(duì)我們有什么幫助呢?它就是我們實(shí)現(xiàn)Dynamic Dispatch的核心。
我來(lái)舉一個(gè)簡(jiǎn)單的例子。
lily = Module[{me},
me["name"] = "Lily";
me["say"] := Function[{}, Print["My name is ", me["name"]]];
me
]
lily["say"][]
OK,把這段代碼仔細(xì)品味品味,我的面向?qū)ο笏枷胍呀?jīng)昭然若揭。
我不想過(guò)多解釋這段代碼,只希望你好好考慮如下的問(wèn)題:lily是什么?lily[“say”][] 是怎么執(zhí)行的?
這個(gè)解決方案的誕生不是靈光一現(xiàn),它足足折磨了我三天三夜;感謝《計(jì)算機(jī)程序的構(gòu)造與解釋》,這個(gè)解決方案幾乎完全是由它給出的。
this指針的實(shí)現(xiàn)
那么this指針呢?你肯定立馬可以看出來(lái),上面的me就是this指針。對(duì)于類的域函數(shù)定義,包含兩種類型:第一種是靜態(tài)函數(shù),定義成 Function[{x},y],y僅僅是x的函數(shù),與對(duì)象無(wú)關(guān);第二種是成員函數(shù),定義成 Function[{this},Function[{x},y]],y是this和x的函數(shù),this代表傳入的對(duì)象。在對(duì)象中dispatch函數(shù) 時(shí),根據(jù)嵌套的Function層數(shù)決定是否是靜態(tài)函數(shù)。至此,我們的面向?qū)ο篌w系基本架構(gòu)完成。
以下是使用我編寫的程序包實(shí)現(xiàn)的小程序。
<< DabaoClass`
man = DefClass["man", {year, name}]
AddField[man, "age"]
man["age"] =
Function[{this}, Function[{}, First[DateList[]] - this["year"] + 1]];
AddField[man, "say"]
man["say"] =
Function[{this}, Print["My name is ", this["name"], "\nI'm ",
this["age"][], " year's old"] &];
tom = New[man];
tom["year"] = 1989;
tom["name"] = "tom";
tom["say"][]
tom["age"][]
運(yùn)行結(jié)果
My name is tom
I'm 23 year's old
程序包下載
技術(shù)鄰APP
工程師必備
工程師必備
- 項(xiàng)目客服
- 培訓(xùn)客服
- 平臺(tái)客服
TOP




















