andyhu1007 发表于 2013-2-7 21:14:19

Rails每周一题(十七): 从Singleton Class看Ruby的对象模型

我们可能了解Ruby的singleton method概念,它指的是一个对象独有的方法。
 
下面举个简单的例子,首先来定义一个类:
 
class ExampleClass   def foo       puts 'foot'   endend 然后创建两个实例,并且给第二个实例增加一个singleton method:
 
example1 = ExampleClass.newexample2 = ExampleClass.newdef example2.barputs 'bar'endexample2.bar 它的输出结果是:
 
"bar" 
而从下面这个结果我们可以看到,example1并不具有bar这个方法:
 
example1.bar#=> undefined method 'bar' for ...(No Method Error) 
这就是所谓的singleton method。
 
我们还可以通过另外一种方式给example2定义一个singleton method:
 
class << example2def bar      puts 'bar'endend 
那Ruby是如何实现singleton method的呢?
 
 
当我们为一个特定的对象定义一个方法时,在对象和它的“真正类”之间会插入一个新的匿名类,而这个singleton method会定义在这个类中。所以,当我们调用bar方法时,解释器首先会在这个匿名类中寻找方法的定义,然后才会去“真正的类”ExampleClass那里去寻找。在Ruby里面,把这个匿名类称之为“singleton class”或者“shadow class”。
 
让我们来看一下这个singleton class到底是什么:
 
puts example2.classclass << example2puts selfend 
输出结果:
 
 
ExampleClass#<Class:#<ExampleClass:0x28305d>> 
可以看到,bar方法定义所在的类的的确确并不是ExampleClass,而是一个匿名类。
 
类方法
 
在Ruby中,我们往往可以通过以下几种方式给一个类定义一个类方法:
 
class ClassMethodExampledef self.foo    puts 'class foo'endclass << self    def bar      puts 'class bar'    endendendclass << ClassMethodExampledef baz    puts 'class baz'endenddef ClassMethodExample.torputs 'class tor'endClassMethodExample.fooClassMethodExample.barClassMethodExample.bazClassMethodExample.tor 
输出结果为:
 
"class foo""class bar""class baz""class tor"  
看了这种定义方式,是否发现它和给一个对象增加一个singleton method的方式很相似呢?
 
没错,其实他们就是一样的。在Ruby里面,一个类是一个实例,是类Class的一个实例。那我们就很好理解这两种方式的一致性:给类增加一个类方法,不就是往“类”这个实例中增加一个singleton method么?
 
还是让我们来看看Ruby的对象模型吧:
 

http://www.agoit.com/upload/attachment/133668/12148297-d78f-39e5-8db7-db08e52483cd.png
 
(图1:Ruby的对象模型)
 
上图中绿色代表”普通“类,蓝色代表meta-class。虚线代表类与对象间的关系(instance of),箭头指向的方向为”类的方向“。实线代表继承关系,箭头指向的方向为“父类”方向。
 
上例中的ExampleClass只是上图中所指的“普通类”Class的一个实例,可以通过下面的方法印证:
 
puts ExampleClass.new.classputs ExampleClass.class 输出:
 
"ExampleClass""Class" 
而相对于ExampleClass而言,类Class就是它的meta-class。
 
所有的”最低级类“都是类Class的实例?没错。实际上,我们需要注意一点:类名是一个常量。比如当我们调用ExampleClass.new时,我们实际上是向一个Class类的实例发送消息,而类名这个常量指向的就是这个实例。
 
再来看看,ClassMethodExample类中的类方法,实际上就是这个Class类实例的singleton method,它们也存在于这个实例的singleton class中:
 
puts ClassMethodExample.instance_methods.inspectputs ClassMethodExample.class.instance_methods.inspectclass << ClassMethodExampleputs self.instance_methods.inspectend 输出结果:
 
"['methods', 'freeze', ...]""['new', 'allocate', ...]""['bar', 'tor', ...]" 
完毕。
 
Reference:
 
http://olabini.com/blog/tag/singleton-class/
 
http://www.hokstad.com/ruby-object-model.html
 
http://www.rubycentral.com/book/tut_classes.html
页: [1]
查看完整版本: Rails每周一题(十七): 从Singleton Class看Ruby的对象模型