Singleton class
是类,又名metaclass或者 eigenclass。是谈到Ruby object model时绕不开的话题。
方法调度
要充分理解Singleton class,必须要弄清楚Ruby中的方法调度(method dispatching)。看例子:
class Vehicle
def initialize(kms)
@kms = kms
end
def drive
puts "let's go!"
end
end
car = Vehicle.new(20_000)
car.drive
上述代码定义了Vehicle类,并创建了实例car,对car调用了方法drive。下图展示了内存中对Vehicle类和car实例的表示。
内存中,实例car是通过C struct来表示的,包含了实例变量的列表。同时,实例对象car还包含了一个kclass指针,指向实例化该对象的类-Vehicle。Vehicle类中包含了实例方法列表及指针super,该指针指向了Vehicle类的superclass - Object (默认情况下,所有类的父类)。
实际上实例对象car并不知道自己有个drive方法,它会通过表示它的C struct中的kclass指针找到它的类,然后在类(Vehicle)的实例方法列表中找到这个drive方法,并真对实例对象car调用这个方法。
由于 "Everything in Ruby is object",类也是对象,针对类调用方法的时候,也会遵循如上的策略,下面的例子在上面代码的基础上,加入了类变量和类方法:
class Vehicle
@@registry = []
def self.register(vehicle)
@@registry << vehicle
end
# ...
end
car = Vehicle.new(20_000)
Vehicle.register(car)
上述代码例子中,定义了类变量 - @@registry(2个@开头的变量是类变量),以及一个类方法register。内存中的对象(包括Vehicle类)表示如下:
不过,类方法register在哪里?Vehicle类中只包含了实例方法列表,不会包含类方法的列表。但是,不管是实例对象,还是类对象,进行方法调度的机制应该是一样的。这意味着,Vehicle类也必须通过kclass指针到它的类中去找到这个register方法。但是,我们不能把这个类方法register方法到Class类中,否则,所有的类都会有个register方法。
Ruby就是靠Singleton class类这个问题。
Singleton class登场
Ruby会为实例对象/类对象创建一个Singleton class。这个class只是只为这个特定的对象创建的,并对我们是隐藏的。当针对某个对象调用方法的时候,首先到这个对象的Singleton class中去查找(如果有Singleton class的话),找到就会调用。
(图中#A表示类对象A的Singleton class,#a表示实例对象a的Singleton class)
上图实际进行了适当简化,文章末尾会给出完整的object model。
当通过self.register定义类方法的时候,实际上是在告知Ruby为Vehicle类创建它的Singleton class,并在其中添加这“实例方法”register。
如何告知Ruby为实例对象创建Singleton class呢?例子如下:
car = Vehicle.new(20_000)
def car.start # Ruby会为实例对象car创建Singleton class,并将方法start放在其中
puts "starting..."
end
上述代码会为实例对象car创建Singleton class - #car。
不过,当对实例对象car调用class方法的时候,返回是类Vehicle,并不是car的Singleton class(记得上面有提过,Singleton class对我们是隐藏的)。不过,由于#car的super 指向了Vehicle类,因此,我们仍然可以通过super来改变Vehicle中的方法行为,达到覆写的目的:
car = Vehicle.new(1000)
bus = Vehicle.new(3000)
def car.drive
print "I'm driving a car! "
super
end
car.drive # "I'm driving a car! let's go!"
bus.drive # "let's go!"
关于类对象的Singleton class
我们编写个稍微复杂点的例子:
class Vehicle
@@registry = []
def self.register(vehicle)
@@registry << vehicle
end
end
class Car < Vehicle
def self.register(car)
# register car plate
super
end
end
some_car = Car.new
Car.register(some_car)
上述程序中对象的内存表示:
注意图中#Car的super指针是指向#Vehicle的,这种关系,让Car中的类方法register调用(super)父类中的类方法成为了可能。
#Object的super是指向Class的。所有的Ruby类继承自Object,它们对象的Singleton class继承自#Object,最终继承自Class。
至此,我们能从Ruby的object model中总结出2个规则:
- 实例对象的Singleton class的superclass是这个对象的类。
- 类对象的Singleton class的superclass是这个类的superclass的Singleton class。