Ruby 的 Singleton 類(lèi)
Ruby 對(duì)象模型有一個(gè)很特殊的存在,他就是單例類(lèi)(Singleton Class),本章節(jié)中我們會(huì)對(duì)單例類(lèi)做一個(gè)簡(jiǎn)單的介紹。
1. 什么是單例類(lèi)
讓我們從一個(gè)簡(jiǎn)單的例子開(kāi)始:
實(shí)例
class Person
def a_name
'Andrew'
end
end
person = Person.new
puts person.a_name
puts person.class.instance_methods.grep /name/
# ---- 輸出結(jié)果 ----
Andrew
a_name
這個(gè)是一個(gè)簡(jiǎn)單的例子,在類(lèi)的本質(zhì)中我們學(xué)習(xí)到了,如果要查找一個(gè)對(duì)象中的方法,要從他的類(lèi)中查找,因?yàn)榉椒ǘ际嵌x在類(lèi)中的。
類(lèi)其實(shí)也是對(duì)象,那么當(dāng)我們定義類(lèi)方法的時(shí)候,同理,方法應(yīng)該存在于Class類(lèi)中的,但是答案卻是否定的。
實(shí)例:
class Person
def self.list
[ 'Andrew', 'Tom', 'Alice' ]
end
end
p Person.list
p Person.class.instance_methods.grep /list/
# ---- 輸出結(jié)果 ----
["Andrew", "Tom", "Alice"]
[]
那么這個(gè)類(lèi)方法到底放在了哪里呢,答案就是存在于單例類(lèi)中。
我們可以使用singleton_class來(lái)獲取一個(gè)對(duì)象的單例類(lèi)。
實(shí)例:
class Person
def self.list
[ 'Andrew', 'Tom', 'Alice' ]
end
end
p Person.list
p Person.singleton_class.instance_methods.grep /list/
# ---- 輸出結(jié)果 ----
["Andrew", "Tom", "Alice"]
[:list]
**解釋?zhuān)?*當(dāng)我們定義self.list的時(shí)候,實(shí)際上是告訴Ruby打開(kāi)self的單例類(lèi),并在其定義list方法。
同理可知,所有的對(duì)象他們的方法實(shí)際上都存在于單例類(lèi)之中。
實(shí)例:
class Person
def a_name
'Andrew'
end
end
person = Person.new
puts person.a_name
puts person.singleton_class.instance_methods.grep /name/
# ---- 輸出結(jié)果 ----
Andrew
a_name
2. 單例類(lèi)與類(lèi)、對(duì)象之間的關(guān)系
現(xiàn)在讓我們定義一個(gè)Student類(lèi)和Person類(lèi)。
實(shí)例:
class Person
def a_name
'Andrew'
end
end
class Student < Person
end
student = Student.new
p student.a_name
# ---- 輸出結(jié)果 ----
'Andrew'
讓我們輸出它的祖先鏈:
p Student.ancestor
# ---- 輸出結(jié)果 ----
[Student, Person, Object, Kernel, BasicObject]
讓我們從頭輸出一下它祖先鏈類(lèi)的部分:
p student.class
p student.class.superclass
p student.class.superclass.superclass
p student.class.superclass.superclass.superclass
# ---- 輸出結(jié)果 ----
Student
Person
Object
BasicObject
現(xiàn)在讓我們?cè)谥虚g輸出它的每一個(gè)對(duì)象的單例類(lèi):
p student.singleton_class
p student.class
p student.class.singleton_class
p student.class.superclass
p student.class.superclass.singleton_class
p student.class.superclass.superclass
p student.class.superclass.superclass.singleton_class
p student.class.superclass.superclass.superclass
p student.class.superclass.superclass.superclass.singleton_class
# ---- 輸出結(jié)果 ----
#<Class:#<Student:0x007f82f4170060>>
Student
#<Class:Student>
Person
#<Class:Person>
Object
#<Class:Object>
BasicObject
#<Class:BasicObject>
Tips:?jiǎn)卫?lèi)輸出前面會(huì)有一個(gè)
#,比如:通常我們說(shuō)Person的單例類(lèi)是#Person。
實(shí)例對(duì)象的單例類(lèi)的超類(lèi)是實(shí)例對(duì)象的類(lèi)。
p student.class
p student.singleton_class.superclass
# ---- 輸出結(jié)果 ----
Student
Student
類(lèi)的單例類(lèi)的超類(lèi)等于類(lèi)的超類(lèi)的單例類(lèi)。
p student.class.singleton_class.superclass
p student.class.singleton_class.superclass.superclass
p student.class.singleton_class.superclass.superclass.superclass
p student.class.superclass.singleton_class
p student.class.superclass.superclass.singleton_class
p student.class.superclass.superclass.superclass.singleton_class
# ---- 輸出結(jié)果 ----
#<Class:Person>
#<Class:Object>
#<Class:BasicObject>
#<Class:Person>
#<Class:Object>
#<Class:BasicObject>
單例類(lèi)同樣也是Class類(lèi)的對(duì)象。
p student.singleton_class.class
p student.class.singleton_class.class
# ---- 輸出結(jié)果 ----
Class
Class
3. 打開(kāi)單例類(lèi)
我們可以通過(guò)class <<來(lái)打開(kāi)單例類(lèi)并且在其中定義方法。
實(shí)例:
普通實(shí)例對(duì)象:
class Person
end
person = Person.new
class << person
def name
'Andrew'
end
end
puts person.name
# ---- 輸出結(jié)果 ----
Andrew
對(duì)于類(lèi)您同樣可以這么使用:
class Person
end
class << Person
def list
['Andrew', 'Alice']
end
end
p Person.list
# ---- 輸出結(jié)果 ----
["Andrew", "Alice"]
或者在類(lèi)的內(nèi)部打開(kāi)單例類(lèi):
class Person
class << self
def list
['Andrew', 'Alice']
end
end
end
p Person.list
# ---- 輸出結(jié)果 ----
["Andrew", "Alice"]
4. 小結(jié)
本章節(jié)我們學(xué)習(xí)了 Ruby 中單例類(lèi)的知識(shí),學(xué)習(xí)到了:
- 定義對(duì)象的方法的時(shí)候(包括類(lèi)),所有的方法都是定義到了單例類(lèi)中。
- 每一個(gè)對(duì)象都有單例類(lèi)(包括類(lèi))。
- 實(shí)例對(duì)象的單例類(lèi)的超類(lèi)是實(shí)例對(duì)象的類(lèi)。
- 類(lèi)的單例類(lèi)的超類(lèi)等于類(lèi)的超類(lèi)的單例類(lèi)。
- 單例類(lèi)同樣也是
Class類(lèi)的對(duì)象。 - 我們可以通過(guò)
class <<來(lái)打開(kāi)單例類(lèi)并定義方法。
杜驍 ·
2025 imooc.com All Rights Reserved |