# 類別跟模組有什麼不一樣？

> 

Published: 2015-03-24
URL: http://cdn.kaochenlong.com/class-and-module

---

在網路上常看到一些介紹 Ruby 裡類別（class）跟模組（module）的差別，有人說他們兩個差別很大，是完全不同的東西。事實上，類別跟模組是很像的。可能很多人不知道，類別跟模組是有血緣關係的，如果你試著這樣做：

```ruby
puts Class.superclass
```

你會得到 `Module` 這個類別。也就是說，在 Ruby 裡，「類別」其實就是「模組」的後代，類別根本就是繼承自模組來的。既然是同一個體系，自然沒有太多的差異。

&lt;!--more--&gt;

### 那差別是什麼?

最明顯的差別，當然就是一個是用 `class` 來定義，一個是用 `module` 來定義。至於前、後代功能上的差別，我們只要寫幾行簡單的程式就可以看得出來：

```ruby
# 前、後代的類別方法差異：
p Class.methods - Module.methods

# 或直接這樣寫：
p Class.methods(false)
```

上面這段會得到 `[]` （空陣列），表示他們在類別方法上並沒有差別。再來看看實體方法的差別：

```ruby
# 前、後代的實體方法差異：
p Class.instance_methods - Module.instance_methods

# 或直接這樣寫：
p Class.instance_methods(false)
```

會得到以下結果：

```ruby
[:allocate, :new, :superclass]
```

其中，`allocate` 跟 `new` 跟產生實體（instance）有關，`superclass` 跟繼承有關。

也就是說，類別比模組多了可以「產生實體」的能力以及「繼承」的能力。

### 那用途上有什麼差別?

請大家先思考一個問題：「如果我有一個小貓類別，我希望這個小貓會飛，你會怎麼做?」

1. 直接寫一個有飛行功能的小鳥類別，然後再叫小貓類別去繼承它?
2. 直接把飛行功能寫在小貓類別裡?

第 1 種做法的設計有點怪怪的，好好的貓不當，為什麼要去當鳥? 為了想要有飛行功能就去當別人家的小孩...

第 2 種做法看來似乎可行，但如果之後又有個「我希望我的這個小狗類別也會飛!」的需求，那這樣又得在小狗類別裡寫一段飛行功能，程式碼沒辦法共同。

這時候，模組就可以派上用場了。

```ruby
module Flyable
  def fly
    puts &quot;I can fly!&quot;
  end
end

class Cat
  include Flyable
end

kitty = Cat.new
kitty.fly        # =&gt; I can fly!
```

在上面這段範例中，我做了一個飛行模組（Flyable），然後小貓類別不用特別寫什麼功能，就只要把這個飛行模組掛上去（include）就搞定了。

如果之後小狗類別也想要會飛的話，只要這樣：

```ruby
class Dog
  include Flyable
end
```

小狗也會飛了。

### 要用繼承還是要用模組?

基本上，如果你發現你要做的這個功能，它可能在很多不同體系的類別裡都會用得到，那你可以考慮把功能包在模組裡，然後在必要的時候再 include 進來即可。

如果你還是不知道到底類別跟模組有什麼差別，我再舉二個例子。

不知道大家有沒看過[火影忍者](http://zh.wikipedia.org/wiki/%E7%81%AB%E5%BD%B1%E5%BF%8D%E8%80%85)這部漫畫，漫畫裡的主人公之一，宇智波佐助，因為他們家族血統的關係，他寫輪眼這個功能是天生就有的，這個功能是從他的家族「繼承」來的。而佐助的老師，旗木卡卡西，他雖然也有寫輪眼功能，但他的寫輪眼並非繼承來的，事實上是他在年輕時候 include 了某個寫輪眼模組，所以才有這個效果。

另一個例子，[海賊王](http://zh.wikipedia.org/wiki/ONE_PIECE)漫畫裡，魯夫本來是普通人，但在偶然的機會下，他 include 了橡膠果實之後，他就有了橡膠人的能力了，並不是因為他老爸是橡膠人所以他才是橡膠人。

以上，希望能讓大家在使用類別跟模組時有更進一步的認識 :)


