[Day12] 啊你說這個不能吃是嗎?
哈囉!今天要跟大家介紹的是**模組(Module)**。
在 Ruby 的世界裡,模組是一個特殊又好用的東西,它就跟大名鼎鼎「惡魔果實」一樣,只要吃下去就能獲得那顆果實的特殊能力(完全是個不用靠爸就能成為主角的神奇道具啊!)
在理解模組時,可以想成是它加裝了一個東西原本沒有的功能,大概就像這樣:
這真是太神奇了傑克!
有了模組,我們就不需要使用昨天介紹到的類別繼承,那麼,要如何做到這件事呢?
include
請先詳閱以下使用說明書:
先定義一個模組 Floatable
:
模組的命名規則就和類別一樣,也必須是大字英文字母開頭的常數。
1 | module Floatable |
再定義一個 Bicycle
的類別:
1 | class Bicycle |
產生一個 your_bike
實體,然後使用 float
方法試試看:
1 | your_bike = Bicycle.new |
居然失敗了!為什麼?
因為沒有在腳踏車上裝上可以浮起來的氣墊啊!怎麼可能會成功!
— 需要在類別裡使用 include
來裝模組!—
在 Bicycle
類別裝上剛剛做好的 Floatable
模組吧!
1 | class Bicycle |
重新產生一個 my_bike
實體,然後使用 float
方法:
1 | my_bike = Bicycle.new |
嘿嘿~現在我的腳踏車可以浮在水面上了!
extend
接著,我們再來看看更神奇的 extend
:
假如你今天有一顆引擎的模組,然後把它裝在腳踏車上,腳踏車從此以後就可以用引擎運轉前進了!不過,如果想把腳踏車改造成氮氣噴射的功能,變成阿姆斯特朗旋風噴射阿姆斯特朗砲
的話呢?
這時候就會用上讓模組擴充模組的 extend
了!
廢話說完了,接著來看 code:
1 | module Engine |
看出來了嗎? 原本的 Engine
模組在被 include
後,只是讓腳踏車可以用引擎運轉,但 Acceleration
模組被 extend
後則徹底改造了腳踏車這個類別,讓它完全升級為一種不同的交通工具了(誤)
但如果讓 max
呼叫 accelerate
方法或是讓 Bike
呼叫 run
:
1 | max.accelerate |
就都找不到方法了,所以…
說人話版本 =>
1 | Bike.accelerate # 類別方法 / 用 extend 引入 |
明天會再介紹什麼是類別方法和實體方法!(挖坑)
聽說模組和類別很像?
是的,他們很像。
譬如名字都是大寫字母開頭、裡面會放一些方法。在專案裡,如果只看到一個大寫開頭的常數,並沒有辦法確定現在看到的是模組還是類別!不過,它們還是有一些明顯的差異。
舉個例子,可能很多人在純真的童年時會夢想像鳥類一樣在天上飛,在 20 世紀初,萊特兄弟發明了可以載人的飛機,但直到今天,人們仍然不算是學會了飛行。
如果真的要讓人類可以飛,該怎麼做?
首先,鳥類這個類別應該會有一個 fly
的方法,
1 | class Bird |
然後繼承它?class Human < Birdend
等等!我們的祖先又不是鳥類,所以不應該使用類別繼承吧!
那掛載一個會可以讓人飛行的模組?
1 | module Flyable |
我們終於成功裝上了 Flyable
!從此以後,人類就可以飛了!
Class
和 Module
的方法數量
瞎扯了一堆,接著我們直接進程式裡看看:
1 | # 查詢 Class 和 Module 的方法和數量 |
instance_methods.count
可以幫我們計算一個類別能使用的方法有多少,可以發現雖然兩者的方法都很多,但 Class
比 Module
硬是多出了 3 個方法!
來看看多出的是哪幾個:
1 | p Class.instance_methods(false) |
由於 Module
少了 :new
, :allocate
, :superclass
這些方法 ,所以:
- 模組沒辦法
new
一個新的實體。 - 模組也
無法繼承
別的模組。
1 | m = Module.new |
1 | m.new |
Namespace::
namespace
?這又是什麼?想像一下,我的車有一顆引擎,你的車也有一顆引擎,但你開的是 BMW 旗艦 V12 雙門跑車,我開的是 Toyota Camry (Camry 錯了嗎?),那這兩輛車會是同樣的車嗎?很明顯不是!(怒)
那要怎麼解決這種問題呢,簡單來說,namespace
就是為了避免叫到同名類別,導致程式無法判讀的問題。我們在呼叫類別時,可以連名帶姓地呼叫:
譬如專案裡常常會看到的:
1 | # 類別(模組)::類別 |
如此一來,我們就能很清楚地知道 User
類別是繼承自 Base
類別,而這個 Base
類別是屬於 ActiveRecord
這個模組(或類別)裡的,其他地方如果有叫 Base
的類別都不是!
有興趣的朋友可以看看龍哥的這篇大作:
Ruby 語法放大鏡之「有時候會看到有兩個冒號寫法是什麼意思?」
說了這麼多,今天就先到這邊囉!
相信大家應該都認識模組了!明天見囉!
旗木卡卡西:是不是忘了介紹我?寫輪眼才是最強的模組啊!