iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 10
0
自我挑戰組

Metaprogramming Ruby and Rails系列 第 10

Day 10 -- Singleton class In Ruby 神秘的匿名者 PART II

The Truth About Class Method

"Class methods are a special kind of Singleton Method - and just as baffling"

定義類別方法時需在方法前加上 self。

class Cat < Animal
  # instance method for instance object
  def speak
    "meow"
  end
  
# class method is also a singleton method
  def self.jump
    "jumping"
  end
end
p Cat.singleton_methods # => [:jump]

在上面程式碼中,可從 Cat.singleton_methods 證實類別方法也是 singleton method。

Singleton Classes and Inheritance

有了對 Singleton classes 的基本認識後,本章節來聊聊 Singleton classes 、classes 與 superclasses 之間的關聯。
以下面的程式碼為例子:

class Animal
  # instance method for every instance object of Animal
  def run
    @str = "running"
  end
end

class Cat < Animal
  # instance method for every instance object of Cat
  def speak
    "meow"
  end
end

# Add a class method/singleton method to Animal class
class Animal
  class << self
    def a_class_method
      "C.a_class_method"
    end
  end
end
kitty = Cat.new

# Add a singleton method to kitty object
class << kitty
  def scratch
    "scratching"
  end
end

https://ithelp.ithome.com.tw/upload/images/20200925/20120868OoIRSiKK6a.png
箭頭 C 指向的物件並不等於類別方法(class method)住的地方,因為類別方法並不知道 singleton class 的存在。舉例來說:如果你問 kitty 的類別是什麼? Ruby 是會回傳 Cat ,但是其實 kitty 的類別應該是 kitty 的 singleton class, aka " #kitty " 。

Cat.superclass                      #  =>  #<Class:Animal>
Animal.singleton_class              #  =>  #<Class:Animal>
Cat.singleton_class                 #  =>  #<Class:Cat>
Cat.singleton_class.superclass      #  =>  #<Class:Animal>
Animal.singleton_class.superclass   #  =>  #<Class:Object>

( # 代表是 singleton class, #Cat 就是 singleton class of Cat)

可從上圖得知:
#Cat 的 superclass 是 #Animal,同時也是 Animal 的 singleton class。
同樣地,#Animal 的 superclass 就是 #Object。
因此我們可以這樣說:

" The superclass of the singleton class is the singleton class of the superclass" from Metaprogramming Ruby

昏頭了嗎?其實多看幾次就會懂了!那也許有人會問:為什麼 Ruby 要把 class、superclass 及 singleton class 之間的關聯設計的如此令人困惑呢?答案是因為這樣的設計讓我們可以在子層(subclass)就可以呼叫到父層的類別方法。

Cat.a_class_method         # => "Animal.a_class_method"

也許在 Cat 類別呼叫 Animal 類別所擁有的方法是再正常不過的事情了,不就是繼承所得到的方法嗎?

但是現在終於了解 Ruby 背後運作的幕後工程。


上一篇
Day 9 -- Singleton class In Ruby 神秘的匿名者 PART I
下一篇
Day 11 -- Dynamic Methods Part I
系列文
Metaprogramming Ruby and Rails33

尚未有邦友留言

立即登入留言