Ruby中的单例类
Ruby中的单例类

单例类(singleton class)是个令人困惑的名词,因为它是继承体系中一个匿名且不可见的类。

Directory

什么是单例类?

当你写ruby有一定经验了或者碰到比较喜欢专研ruby实现的人,你一定对单例类这个词不陌生。

有时候它们又被称为本征类(eigenclasses)或是元类(metaclasses)。

它们在Ruby中扮演了重要的角色,是Ruby自身根据需要动态创建的。

它们是没有名字的、被加以限制的常规类,所以你不能创建一个单例类的实例。

单例方法

这里说的单例方法不是设计模式中的单例模式

先看一段代码

class A
  def name
    "alex"
  end
end

a = A.new

def a.greet
  "hello"
end

我们知道调用name方法的时候是先从a对象开始往继承链上找,找到A上就会发现name方法,这时候就调用name。

那么,要是调用greet方法呢?

没错,这时候也是从a对象开始往继承链上找,不过这时候a和A之间有个单例类,这个单例类把greet作为它的实例方法,它在a和A的继承关系的中间。

a -> singleton_class -> A -> Object -> Kernel -> BasicObject

a.singleton_class.instance_methods(false) # 返回[:greet]

现在我们来找点麻烦

class A
  def self.hola
    "hola"
  end
end

既然a的实例方法式存在A上面,那类方法呢?

其实也是单例类,当你创建类方法的时候,ruby会引入一个单例类,放在A继承链上面,就和对象a继承的单例类一样,类方法其实就是那个单例类的实例方法。

a -> singleton_class -> A -> singleton_class -> ···

要是再困难一点呢

module B
  def haha
    "haha"
  end
end

class A
  include B
end

哈哈,要是我通过模块引入一个实例方法你知道它是存在哪的吗?

你可能会以为是下面这样

··· -> A -> singleton_class -> B -> ···

其实你的想法没错,不过,在继承链上,module B并不是真正的在继承链上,继承链上的module B其实也是个单例类,用来指向module B,要是有很多个类都包含了module B,那么只需要添加单例类就行了,实际上module B只有一个

小结

关于单例类其实是cruby为了实现语法的一种内部类,对ruby用户是隐藏的,只能通过singleton_class方法访问,在调用ancestors方法时不会看到单例类,他们被ruby忽略了,同理superclass方法也会跳过单例类。