程式扎記: [ Ruby Gossip ] Advance : 類別 - 匿名單例類別

標籤

2014年11月24日 星期一

[ Ruby Gossip ] Advance : 類別 - 匿名單例類別

Source From Here
Preface
在一些書或文件中會提到,Ruby 中的物件行為,並不一定是類別上定義的行為。例如:


在上面的範例中,Some 類別並沒有定義 other,然而 s 可以呼叫 other,Ruby 稱 other 是 s 的 單例方法。物件可操作的方法是定義在類別中,那麼單例方法是定義在哪呢?答案是 s 的 單例匿名類別Anonymous singleton class),或簡稱單例類別(Singleton class)。

匿名單例類別
單例類別的建立是隱含的,如果你想開啟單例類別,可以使用 class << object 的語法。例如:


以上定義 o 的單例方法 some,相當於:
  1. def o.some  
  2.     puts "some"  
  3. end  
先前談過,如果你要求物件對某個訊息進行回應,物件會看看自己是否有定義單例方法,再看看產生實例的類別上是否有定義方法,現在可以修正為,物件會看看單例類別上是否有定義,再看看產生實例的類別上是否有定義方法。並非所有的物件都可以定義單例方法,例如 Numeric 與 Symbol 實例就不行:


如果你要求物件對某個訊息進行回應,物件會看看單例類別上是否有定義,再看看產生實例的類別上是否有定義方法,這並不是說,物件會有兩個類別定義,你可以想像,Ruby每建立一個物件前,都會先用 Class.new 建立一個匿名類別,再用該匿名類別建立物件,你定義單例方法時,就是定義在該匿名類別上,而 class << object 的寫法,開啟的也就是該匿名類別,因此可擁有物件個體性的功能存在。範例如下:
  1. o = Object.new  
  2. def o.some  
  3.     puts "some"  
  4. end  
  5. o.some  # some  
如果要使用程式碼來模擬以上說明,大致像是:
  1. ANONYMOUS_CLZ = Class.new(Object)  
  2. o = ANONYMOUS_CLZ.new  
  3. class ANONYMOUS_CLZ  
  4.     def some  
  5.         puts "some"  
  6.     end  
  7. end  
  8. o.some # some  
以上只是模擬,實際上單例類別是由 Ruby 執行環境維護,還有一個不同點就是,如果是以下:
  1. o = Object.new  
  2. def o.some; end  
  3. puts o.class # Object  
取得的並不是單例類別,而是建構實例時的類別。有辦法讓你取得單例類別,就是在開啟單例類別時,使用 self 來取得單例類別:


因此,可以定義以下的程式碼,來驗證先前的說明:


從上面的範例可以看到,如果為 Some 的實例 s 定義單例方法,其單例類別的父類別確實是 Some,因此,單例方法仍是遵循 方法查找順序,而不是一個物件若定義了單例方法,就會有兩個類別管理方法查找,而仍是繼承體系下的查找順序。

實際上,可以直接使用 singleton_class 方法取得物件的單例類別。例如:


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!