iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 9
0
自我挑戰組

Metaprogramming Ruby and Rails系列 第 9

Day 9 -- Singleton class In Ruby 神秘的匿名者 PART I

前言

此篇文章對剛學 Ruby 程式語言的朋友們來說,應該算是比較進階的題目。其實我已看過了網路上相關文章後,也是似懂非懂的,ㄧ直到閱讀"Metaprogramming Ruby" 後,才有了較深刻的了解。但文章內如有錯誤或是有不完整的地方都歡迎各位大大不吝指教!

Singleton Method

"A method like this one, which is specific to a single object, is called Singleton Method" from Meatprogramming Ruby

Singleton method 是讓物件自己擁有專屬的方法,任何其它物件或是類別都無法使用。但在開始介紹 singleton method 之前,先回顧昨天所提到的 "查詢方法流程 (method lookup)"。

class Animal
  def run
    @str = "running"
  end
end
class Cat < Animal
  def speak
    "meow"
  end
end
kitty = Cat.new
kitty.run   # => "running"

https://ithelp.ithome.com.tw/upload/images/20200924/201208684aea2mEs1v.png

當 run() 方法被呼叫時, kitty 物件(receiver) 向右尋找 Cat 類別,如果沒有找到再繼續往上層找,直到 run() 方法被找到為止。

接者讓 Ruby 在 kitty 物件上定義一個新方法 scratch(), 如下面程式碼:

kitty = Cat.new
lucy = Cat.new
def kitty.scratch
  "scratching"
end
kitty.scratch             # => "scratching"
kitty.singleton_methods   # => [:scratch]
lucy.scrach               # => (NoMethodError)

如此一來,scratch() 就只能被 kitty 物件所使用,就算再建立新的實例物件 lucy 呼叫 scratch(),也只能得到錯誤訊息 (NoMethodError)。這個 scratch() 方法就稱為 singleton method。
我們知道『實例變數是住在實例物件裡面,而方法是住在類別 』,那 singleton method 是住在哪呢?

  • 選擇 A : 在 kitty 物件上? No,因為 kitty 物件不是類別
  • 選擇 B : 在 Cat 類別上 ? No, 因為如果是在 Cat 類別上,所有的實例物件(包括 lucy 物件)就都可使用 scartch()
  • 選擇 C :在 Singleton class 上 ? YES.

Singleton method 的所在位置並不是那麼明顯是有原因的,其實是在 Ruby 的世界裡,Object (物件) 是可以擁有自己的隱藏類別。這個隱藏類別就是 『 Singleton class 』,雖然也有其他的稱號,例如:anonymous class、eigenclass、metaclass 等…,但在 Ruby 原始碼上是稱為 singleton class。
加上 scratch()方法後,再看看查詢方法流程圖就應該如下圖:
https://ithelp.ithome.com.tw/upload/images/20200924/20120868ARkvhkH7as.png

Accessing Singleton Class

要直接存取 singleton class 可用以下方法:

class << an_object    # an_object是你要存取的Object
  # 放你的程式碼
end

# Create singleton method at instance object level
kitty = Cat.new
class << kitty
  def scratch
    "scratching"
  end
end

kitty.scratch            # => "scratching"
kitty.singleton_methods  # => [:scratch]

# Create singleton method at Class level
class << Cat
  def scratch
    "scratching"
  end
end

Cat.scratch            # => "scratching"
Cat.singleton_methods  # => [:scratch]

最後可以到 rails console 裡看看,其實 rails 大量地使用 Singleton methods。
https://ithelp.ithome.com.tw/upload/images/20200924/20120868UEQXbLJNSJ.png

重點回顧

  • Singleton method 就是讓物件擁有專屬的方法,其他物件或是類別都無法使用。
  • 存取 Singleton class 需要用特別的句法才能打開
class << an_object    # an_object是你要存取的Object
  #放你的程式碼
end

上一篇
Day 8 -- What Happens When You Call a Methods? Part II
下一篇
Day 10 -- Singleton class In Ruby 神秘的匿名者 PART II
系列文
Metaprogramming Ruby and Rails33

尚未有邦友留言

立即登入留言