iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
0
自我挑戰組

滿滿的紅寶石不拿嗎?-- 去吧!我把世界上的一切都放在那裡了! 系列 第 29

Singleton Class 與物件導向 <> 記錄指針不見了!我們該如何前進到下個島嶼 - 滿滿的紅寶石不拿嗎?

[Day29] 記錄指針是海賊王世界裡一種外觀像手錶,中央為球形的特殊羅盤。可以偵測並記下偉大航路內各個島嶼放出的磁場,為海上航行的船隻提供正確的路線。

延續昨天的主題,我們已經知道單體方法是怎麼被定義的,但它既不屬於類別方法,也不是實體方法,那它到底被定義在哪裡呢?

先說結論:單體方法被寫在 Singleton Class 裡。

走過的路 是一陣魔術···
···都化作這目光 吟唱成一首歌

抱歉突然想唱個歌,讓我們進入正題~


Singleton Class 是什麼?

如果是初學 Ruby 這門程式語言的朋友,一開始幾乎不太會接觸到 Singleton Class 的概念。在一般的繼承鍊裡,我們只學過 Class < Object < BaseObject 這種一直往上找,層層相疊的繼承關係。

不過實際上在 Ruby 的物件導向設計裡,還有一個非常神祕的類別,
那就是 Singleton Class

  • 它是設計給單一物件使用的類別
  • 又被稱為 metaclasseigenclass
  • Singleton Class 上定義的方法就是單體方法

回顧昨天的例子:

class Cat
  # ...
end

meme = Cat.new

def meme.feet      
  puts "有穿白襪"
end

meme.feet          # => 有穿白襪

雖然單體方法 feet 是寫在類別的外面,但 Ruby 其實有偷偷為 meme 準備了一個 Singleton Class ,而 feet 方法就被定義在裡面:

class Cat
  # ...
end

meme = Cat.new

# singleton class of meme
def meme.feet
  puts "有穿白襪"
end
# end

meme.feet          # => 有穿白襪

有看到 Singleton Class 嗎?

沒看到?

嗯··· 代表你非常正常!

通常在開了天眼後才看得到

所以泰安老師叫它「跟鬼一樣的類別」!


我要在哪裡找到 Singleton Class

其實我還不知道如何在 irb 裡顯示物件的 Singleton Class,不過,通過類別物件的繼承或許可以看出一點端倪。

繼承最核心的概念就是子層類別的物件可以拿父層類別的方法來用,類別方法也同樣遵循著這套繼承的規則

class Animal
  def self.all
    puts "全部的動物"
  end
end

class Cat < Animal
  def self.all
    puts "貓咪王國!"
  end
end

Cat.all            # => 貓咪王國!

如果有同名的類別方法,則會優先呼叫定義在 Singleton Class 的那個。

昨天有提到,類別方法其實也是單體方法的一種,所以每個類別的類別方法就會定義在自己的 Singleton Class 上,像是這樣:

現在我們知道了,當一個 Ruby 物件在呼叫方法時,會先往 Singlton Class 找看看,沒有的話,會再往上從繼承的類別裡尋找。


Ruby 裡的物件導向:

既然都已經講了 Singleton Class,那就不得不來介紹 Ruby 裡的物件導向了!

「物件導向」這四個字看起來又是個高大上,一開始總覺得如果能說清楚這個概念,好像自己會變很聰明,但事實上,它就只是個語言的設計概念。(另一個事實則是我笨)

接下來會用到這兩個方法:

方法 說明
superclass 尋找自己繼承的父層類別
class 尋找自己所屬的類別

superclassclass 能有助於更加釐清 Singleton Class 以及 Ruby 裡物件導向的概念。

繼續沿用剛才的例子,並用這兩個方法來看看吧!

class Cat
  # ...
end

meme = Cat.new

meme.class              # => Cat
meme.superclass         # => NoMethodError (undefined method `superclass' for #<Cat:0x00007fd482123eb0>)

咦? superclass 噴錯了!不過沒關係,因為實體物件本來就沒有繼承的父層類別,繼續來看:

Cat.class               # => Class 
Cat.superclass          # => Object 

Cat 這個類別是屬於一個叫做 Class 的類別,或者說,在 Ruby 裡,所有的類別都屬於 Class 這個類別。

Cat 這個類別是繼承自一個叫做 Object 的類別,"Object",也就是物件的意思,以一個物件導向的語言來說,出現這個名字很合理,繼續看下去:

我們來對 Class 試試看吧:

Class.class             # => Class 
Class.superclass        # => Module 

這次出現了有趣的事情,果然全天下的類別都是屬於 Class 這個類別,因此 Class 所屬的類別也是 Class 自己。

Class 繼承的類別居然是 Module ! 這不是模組嗎?不過仔細一瞧才發現大寫的 Module 是類別,小寫的 module 則是模組,只是,Ruby 設計者沒想過會讓大家困惑嗎XDDD

做一個模組出來試試看:

module Flyable
end

Flyable.class           # => Module 
Flyable.superclass      # => NoMethodError (undefined method `superclass' for Flyable:Module)

Flyable 這個模組屬於 Module 這個類別,而 Flyable 沒有向上的繼承類別(這是因為 Ruby 裡的模組本來就無法繼承)

但令人驚訝的是 Class 竟然是繼承自 Module !當初在學習時,就有發現模組和類別兩個概念很像,但我原本一直以為模組可能是類別的副產品之類的,

沒想到···竟然是反過來
真是世事難料啊!!!

接著我們來看看這個 Object

Object.class            # => Class 
Object.superclass       # => BasicObject 

不出所料,Object 的類別是 Class,而繼承自 BasicObject 類別這個又是什麼?名字怎麼都取這麼像啊!

BasicObject.class       # => Class 
BasicObject.superclass  # => nil 

BasicObject 的類別也是 Class,而再往上就沒有了!

目前可以得到像這樣的圖:

最後來看 Module

Module.class            # => Class 
Module.superclass       # => Object 

嗯···類別是 Class,然後繼承自···咦!Object!那不就

Object.class            # => Class 
Class.superclass        # => Module 
Module.superclass       # => Object 

你們這樣繞來繞去,弄得我頭很痛啊!還好網路上已經有大大梳理好它們彼此之間的關係

看圖是不是清楚多了呢?
說實話,韓劇每個角色的關係圖都比這都複雜多了!


今天的文章就先到這裡了,

以上就是我對 Ruby 物件導向的理解,自己覺得這篇的脈絡有點亂,就和思緒一樣,可能也有一些理解錯誤的地方,大大們如果看到的話還請不吝指出,日後還會繼續進行釐清和整理的。

覺得好像感冒了...頭好昏啊!


參考來源
Metaprogramming in Ruby 2 - The Object Model
speedred - Ruby 的繼承鍊 (1) - 如何實踐物件導向


上一篇
Singleton Method <> 是「百獸海賊團」!碰上四皇凱多有勝算嗎?- 滿滿的紅寶石不拿嗎?
下一篇
Enumerator <> 一旦上了船,程式就是不會背叛你的夥伴 - 滿滿的紅寶石不拿嗎?
系列文
滿滿的紅寶石不拿嗎?-- 去吧!我把世界上的一切都放在那裡了! 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言