那麼我們一樣套路呢,我們,我們來把這個toString也把它變成一個instance function
那toString這個東西啊,原本是這麼寫的,我把一個date object丟進來,
然後這個object,句式就是.year,.month,.day之類的。
可能它原本 被用到的地方是這裡,是我想要print birthday
dictionary的時候, 每當我找到一個人,我就去說,他哪一天生的,這個時候我要把它的date
toString這樣 好那麼我們現在要改得,改什麼就很簡單嘛,首先把它移到date裡面去,
那其次,這裡剛剛有一個 birthday
object,對吧有一個date object,現在我們就改成self,因為就是那個invoking
object,那這個時候就用self來 .year,.month,.day,哦基本上都一樣,就是變成是這個object.-
date 還是那個object.date一樣的道理,然後呢,在呼叫它的地方,
就跟剛剛一樣,就改啦,變成是以物件為主體,哪一個物件,哪一個date
來,我問它,哎,告訴我你要印的話,你的字串想要長什麼樣子吧! 它就告訴我,變成是以物件為主體。
這樣子的話呢,我們就完成了這個toString把它變成instance function
的這個任務啦,今天呢,大家倒是可以想一個問題 就哎,好啊,
那toString也改了,那這個printBdayDict這個要不要改? 這個要不要把它變成一個instance
function呢?哦答案大概是不要。
原因是這個東西並不 是一個date object身上應該要有的operation,對吧
我們今天呢,比如你看這個參數,這個參數是一個birthday的dictionary 好所以是一個dictionary拿來我們在它裡面攪和印東西等等等。
這一個dictionary裡面可是 包含著一大堆的date啦,所以並不是一個date拿來,你就可以對著它說,嘿!
date,告訴我你的這個整個dictionary長什麼樣子之類的,你辦不到,這一個- object是一個dictionary
的一部分,顯然是不可能做到這種事情的。
好所以這個函數, printBdayDict它既然不是date的一部分,那你就不應該嘗試
把它寫成這個date object的一個operation啦!
那麼另外呢,還有一個函數是isLeap。
isLeap這個東西哦,我們之前看一下,是這樣子
給我一個year,我會呢寫一個isLeap,然後呢我會判斷這個所謂的年份是不是
一個閏年,那你仔細想想的話,你應該會回答說,恩這個東西恐怕 也不是一個date
object的一部分,這個沒有錯,好因為一個date object它有三個參數。
這裡你不需要三個嘛,你只需要一個。
好那不過這個當然不構成它不是一部分的理由啦,畢竟你問它
就像有一個人好,人身上有兩個屬性,有姓跟名對吧,那你問
他說先生貴姓,他只會需要用到姓,不表示他不能回答這個問題嘛
好所以今天呢只用到year,它一樣可以是它的一個member function,這個倒是沒有什麼問題。
不過要注意一件事情,我們這個isLeap,這個函數啊 它如果真的變成是instance
function的話,也會有點怪 因為你事實上在別的應用,別的情境下也可以用這個函數的。
你也可以路上隨便抓到一個year,哦就把它丟進去看它是不是 isLeap。
你不是一定要產生一個object才能丟進去。
ok,所以呢,它的確不算是,不應該僅限於是一個date object的一部分
我們應該做的事情是,保留這個函數作為一個global function。
但是我們的date object裡面 呢,也有一個函數,去check一個所謂的給定的date
object 是不是一個leap year。
那做法當然就很簡單啦, 就是我今天我幫我的date一樣define一個函數
這個函數呢,是請問我自己是不是落在一個閏年裡面。
那麼我要做的事情 就是把我的self year拿出來,放進global function isLeap 裡面,它會回答我這個問題。
然後我再return它的答案就可以了。
那麼這個情況下呢,isValid的這個地方,就可以做 一些相對應的改變那,就變得更以object為主體。
就是說,ok self self self self,哎如果我自己是一個leap的話,我就怎樣怎樣如何如何。
好那我們就可以改寫成這個樣子。
那同學們如果看到這個地方,然後不免會想要問一個問題
就是,哎這樣寫固然是ok啦!不過有什麼非這樣寫的理由嗎?
好答案是沒有,在此刻這個例子里,只是幫大家展現說一你可以這麼做。
二你要把一個函數寫成global function或instance function的時候,你應該要
有一個考量哦,這個函數,這個operation,它是這個object的一部分嗎?應- 該是嗎?
它應該要僅限於這個object嗎?哦你應該要考慮這些事情。
那在這個 例子里呢,你照原本的寫法,或者現在的寫法,這個isLeap怎麼寫,其實沒有什麼差別。
好不過,很快你就會看到其它各式各樣的例子。
在我們這整個module裡面,你會看到 物件導向的存在是必要的。
哦你非這樣寫不可,不然很多事情 很難做,那我們現在開始入門嘛,你自然就不覺得事情非這樣做不可,
不過就是打個基礎,好那麼呼叫instance function的時候,我要小心啊
呃比如說這裡吧,哦我們剛剛曾經呼叫過isValidDate,這樣子寫是ok的,用一- 個object
去呼叫它的一個instance function。
那你呢如果把它誤寫成第二種的話, 會怎麼樣,那當這儀器讀到這句話的時候,它會跟你說
哎,這裡有個問題,isValidDate是沒有define的 好為什麼沒有define,因為你沒有說它是誰的
isValidDate,你沒有說它是object的isValidDate 它自然就只會去global
function裡面尋找,那它找不到isValidDate,所以它就跟你說unde- fined啊
所以instance function和global function當然是兩個不同的group,好。
global function就像是散落在你的桌面上的各式各樣的文件,instance
function就是date資料夾裡面有一堆 這個電視機資料夾裡面有一堆等等。
所以你今天沒有說去哪個資料夾裡面去找的話, 那它就會在散落在我桌面上的文件裡面搜尋,找不到就說沒有。
那又或者是呢,如果我寫成最下面的這一種,那這個也是初學者常犯的錯誤, 因為他看到這個instance
function的裡面有一個self,他就覺得我這裡是不是要把自己傳進去 答案是不需要的。
當我們[未知]的語法設計 就是說呢,當我們在這裡寫成我框前這個樣子的時候,
那個birthday,那個invoking object就自己變成我們在這個
函數定義的時候那一個第一個參數,它自己會發生這件事情
所以說如果你再寫一次的話,它會出一個error,這個error是說isValid
Date它應該要date一個參數,但你卻給它兩個。
好你這個時候得要知道,所謂的兩個,就是呼叫的那個人算第一個,你傳進去的算第二個
好所以並不是()裡面的才是參數,對instance function 來說,invoking object就是第一個參數。
好所以這件事情如果有搞清楚的話, 才不會對它的這個,所謂的這個,呃錯誤訊息感到 困擾。
好那我們來這個看一下我們的這個程式嘛,
好我們這裡呢,可以看到我們剛剛已經做了一些這個修正啦,
比如說isValidDate我們把它放在這個date'裡面,toString放在
date裡面,isLeap,我們像這樣子把year拿出來然後放進isLeap函數
然後,這裡有個isLeap,這裡有個StringtoDate,好然後呢我們這個p- rint
birthday一樣在這裡就改成用 b.toString這樣子。
ok,那我們就來試試 看我們這個函數呢,我們這個程式現在在這裡,
這個birthday拿來當做主體,來做呼叫,所以我們就試試看,好那試起來,我們有個-
叫Amy的, 199年這個1月23號生,那我們來一個Bob,
Bob呢就是這個呢1998年 好這個12月10號生的。
好以此類推,好程式就這樣子跑,所以 基本上程式在做的事情是一模一樣的,哦只不過就是說他們在
寫作的邏輯上略做修改。
那again,此刻你沒有看出非這麼做不可的理由。
但是隨著程式越來越複雜,過幾個module你就會發現這麼做確實是有一些好處的。