Source From Here
Preface
在一些書或文件中會提到,Ruby 中的物件行為,並不一定是類別上定義的行為。例如:
在上面的範例中,Some 類別並沒有定義 other,然而 s 可以呼叫 other,Ruby 稱 other 是 s 的 單例方法。物件可操作的方法是定義在類別中,那麼單例方法是定義在哪呢?答案是 s 的 單例匿名類別(Anonymous singleton class),或簡稱單例類別(Singleton class)。
匿名單例類別
單例類別的建立是隱含的,如果你想開啟單例類別,可以使用 class << object 的語法。例如:
以上定義 o 的單例方法 some,相當於:
先前談過,如果你要求物件對某個訊息進行回應,物件會看看自己是否有定義單例方法,再看看產生實例的類別上是否有定義方法,現在可以修正為,物件會看看單例類別上是否有定義,再看看產生實例的類別上是否有定義方法。並非所有的物件都可以定義單例方法,例如
Numeric 與 Symbol 實例就不行:
如果你要求物件對某個訊息進行回應,物件會看看單例類別上是否有定義,再看看產生實例的類別上是否有定義方法,這並不是說,物件會有兩個類別定義,你可以想像,Ruby每建立一個物件前,都會先用 Class.new 建立一個匿名類別,再用該匿名類別建立物件,你定義單例方法時,就是定義在該匿名類別上,而 class << object 的寫法,開啟的也就是該匿名類別,因此可擁有物件個體性的功能存在。範例如下:
如果要使用程式碼來模擬以上說明,大致像是:
以上只是模擬,實際上單例類別是由 Ruby 執行環境維護,還有一個不同點就是,如果是以下:
取得的並不是單例類別,而是建構實例時的類別。有辦法讓你取得單例類別,就是在開啟單例類別時,使用 self 來取得單例類別:
因此,可以定義以下的程式碼,來驗證先前的說明:
從上面的範例可以看到,如果為 Some 的實例 s 定義單例方法,其單例類別的父類別確實是 Some,因此,單例方法仍是遵循 方法查找順序,而不是一個物件若定義了單例方法,就會有兩個類別管理方法查找,而仍是繼承體系下的查找順序。
實際上,可以直接使用 singleton_class 方法取得物件的單例類別。例如:
Preface
在一些書或文件中會提到,Ruby 中的物件行為,並不一定是類別上定義的行為。例如:
在上面的範例中,Some 類別並沒有定義 other,然而 s 可以呼叫 other,Ruby 稱 other 是 s 的 單例方法。物件可操作的方法是定義在類別中,那麼單例方法是定義在哪呢?答案是 s 的 單例匿名類別(Anonymous singleton class),或簡稱單例類別(Singleton class)。
匿名單例類別
單例類別的建立是隱含的,如果你想開啟單例類別,可以使用 class << object 的語法。例如:
以上定義 o 的單例方法 some,相當於:
- def o.some
- puts "some"
- end
如果你要求物件對某個訊息進行回應,物件會看看單例類別上是否有定義,再看看產生實例的類別上是否有定義方法,這並不是說,物件會有兩個類別定義,你可以想像,Ruby每建立一個物件前,都會先用 Class.new 建立一個匿名類別,再用該匿名類別建立物件,你定義單例方法時,就是定義在該匿名類別上,而 class << object 的寫法,開啟的也就是該匿名類別,因此可擁有物件個體性的功能存在。範例如下:
- o = Object.new
- def o.some
- puts "some"
- end
- o.some # some
- ANONYMOUS_CLZ = Class.new(Object)
- o = ANONYMOUS_CLZ.new
- class ANONYMOUS_CLZ
- def some
- puts "some"
- end
- end
- o.some # some
- o = Object.new
- def o.some; end
- puts o.class # Object
因此,可以定義以下的程式碼,來驗證先前的說明:
從上面的範例可以看到,如果為 Some 的實例 s 定義單例方法,其單例類別的父類別確實是 Some,因此,單例方法仍是遵循 方法查找順序,而不是一個物件若定義了單例方法,就會有兩個類別管理方法查找,而仍是繼承體系下的查找順序。
實際上,可以直接使用 singleton_class 方法取得物件的單例類別。例如:
沒有留言:
張貼留言