首页 > 服务端语言 > Ruby 入门教程 > 41 Ruby 的 Singleton 类

Ruby 的 Singleton 类

Ruby 对象模型有一个很特殊的存在,他就是 单例类Singleton Class ),本章节中我们会对单例类做一个简单的介绍。

1. 什么是单例类

让我们从一个简单的例子开始:

实例

class Person
  def a_name
    'Andrew'
  end
end

person = Person.new
puts person.a_name
puts person.class.instance_methods.grep /name/

# ---- 输出结果 ----
Andrew
a_name

这个是一个简单的例子,在类的本质中我们学习到了,如果要查找一个对象中的方法,要从他的类中查找,因为方法都是定义在类中的。

类其实也是对象 ,那么当我们定义类方法的时候,同理,方法应该存在于Class类中的,但是答案却是否定的。

实例:

class Person
  def self.list
    [ 'Andrew', 'Tom', 'Alice' ]
  end

end

p Person.list
p Person.class.instance_methods.grep /list/

# ---- 输出结果 ----
["Andrew", "Tom", "Alice"]
[]

那么这个类方法到底放在了哪里呢,答案就是存在于单例类中。

我们可以使用singleton_class来获取一个对象的单例类。

实例:

class Person
  def self.list
    [ 'Andrew', 'Tom', 'Alice' ]
  end

end

p Person.list
p Person.singleton_class.instance_methods.grep /list/

# ---- 输出结果 ----
["Andrew", "Tom", "Alice"]
[:list]

解释:当我们定义self.list的时候,实际上是告诉Ruby打开self的单例类,并在其定义list方法。

同理可知,所有的对象他们的方法实际上都存在于单例类之中。

实例:

class Person
  def a_name
    'Andrew'
  end
end

person = Person.new
puts person.a_name
puts person.singleton_class.instance_methods.grep /name/

# ---- 输出结果 ----
Andrew
a_name

2. 单例类与类、对象之间的关系

现在让我们定义一个Student类和Person类。

实例:

class Person
  def a_name
    'Andrew'
  end 
end

class Student < Person
end

student = Student.new
p student.a_name

# ---- 输出结果 ----
'Andrew'

让我们输出它的祖先链:

p Student.ancestor

# ---- 输出结果 ----
[Student, Person, Object, Kernel, BasicObject]

让我们从头输出一下它祖先链类的部分:

p student.class
p student.class.superclass
p student.class.superclass.superclass
p student.class.superclass.superclass.superclass

# ---- 输出结果 ----
Student
Person
Object
BasicObject

现在让我们在中间输出它的每一个对象的单例类:

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

# ---- 输出结果 ----
#<Class:#<Student:0x007f82f4170060>>
Student
#<Class:Student>
Person
#<Class:Person>
Object
#<Class:Object>
BasicObject
#<Class:BasicObject>

Tips :单例类输出前面会有一个#,比如:通常我们说Person的单例类是#Person

实例对象的单例类的超类是实例对象的类。

p student.class
p student.singleton_class.superclass

# ---- 输出结果 ----
Student
Student

类的单例类的超类等于类的超类的单例类。

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

# ---- 输出结果 ----
#<Class:Person>
#<Class:Object>
#<Class:BasicObject>
#<Class:Person>
#<Class:Object>
#<Class:BasicObject>

单例类同样也是Class类的对象。

p student.singleton_class.class
p student.class.singleton_class.class

# ---- 输出结果 ----
Class
Class

3. 打开单例类

我们可以通过class <<来打开单例类并且在其中定义方法。

实例:

普通实例对象:

class Person
end

person = Person.new

class << person
  def name
    'Andrew'
  end
end

puts person.name

# ---- 输出结果 ----
Andrew

对于类您同样可以这么使用:

class Person
end

class << Person
  def list
    ['Andrew', 'Alice']
  end
end

p Person.list

# ---- 输出结果 ----
["Andrew", "Alice"]

或者在类的内部打开单例类:

class Person
  class << self
    def list
      ['Andrew', 'Alice']
    end
  end
end

p Person.list

# ---- 输出结果 ----
["Andrew", "Alice"]

4. 小结

本章节我们学习了 Ruby 中单例类的知识,学习到了:

  1. 定义对象的方法的时候(包括类),所有的方法都是定义到了单例类中。
  2. 每一个对象都有单例类(包括类)。
  3. 实例对象的单例类的超类是实例对象的类。
  4. 类的单例类的超类等于类的超类的单例类。
  5. 单例类同样也是Class类的对象。
  6. 我们可以通过class <<来打开单例类并定义方法。
本文来自互联网用户投稿,不拥有所有权,该文观点仅代表作者本人,不代表本站立场。
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
© 2023 PV138 · 站点地图 · 免责声明 · 联系我们 · 问题反馈