原创作者: andyhu1007   阅读:4093次   评论:0条   更新时间:2011-05-26    

我们可能了解Ruby的singleton method概念,它指的是一个对象独有的方法。

 

下面举个简单的例子,首先来定义一个类:

 

class ExampleClass
   def foo
       puts 'foot'
   end
end
 

然后创建两个实例,并且给第二个实例增加一个singleton method:

 

example1 = ExampleClass.new
example2 = ExampleClass.new

def example2.bar
  puts 'bar'
end

example2.bar
 

它的输出结果是:

 

"bar"

 

而从下面这个结果我们可以看到,example1并不具有bar这个方法:

 

example1.bar  #=> undefined method 'bar' for ...  (No Method Error)

 

这就是所谓的singleton method。

 

我们还可以通过另外一种方式给example2定义一个singleton method:

 

class << example2
  def bar
      puts 'bar'
  end
end

 

那Ruby是如何实现singleton method的呢?

 

 

当我们为一个特定的对象定义一个方法时,在对象和它的“真正类”之间会插入一个新的匿名类,而这个singleton method会定义在这个类中。所以,当我们调用bar方法时,解释器首先会在这个匿名类中寻找方法的定义,然后才会去“真正的类”ExampleClass那里去寻找。在Ruby里面,把这个匿名类称之为“singleton class ”或者“shadow class”。

 

让我们来看一下这个singleton class到底是什么:

 

puts example2.class

class << example2
  puts self
end

 

输出结果:

 

 

ExampleClass
#<Class:#<ExampleClass:0x28305d>>

 

可以看到,bar方法定义所在的类的的确确并不是ExampleClass,而是一个匿名类。

 

类方法

 

在Ruby中,我们往往可以通过以下几种方式给一个类定义一个类方法:

 

class ClassMethodExample
  def self.foo
    puts 'class foo'
  end

  class << self
    def bar
      puts 'class bar'
    end
  end
end

class << ClassMethodExample
  def baz
    puts 'class baz'
  end
end

def ClassMethodExample.tor
  puts 'class tor'
end

ClassMethodExample.foo
ClassMethodExample.bar
ClassMethodExample.baz
ClassMethodExample.tor

 

输出结果为:

 

"class foo"
"class bar"
"class baz"
"class tor" 

 

看了这种定义方式,是否发现它和给一个对象增加一个singleton method的方式很相似呢?

 

没错,其实他们就是一样的。在Ruby里面,一个类是一个实例,是类Class的一个实例 。那我们就很好理解这两种方式的一致性:给类增加一个类方法,不就是往“类”这个实例中增加一个singleton method么?

 

还是让我们来看看Ruby的对象模型 吧:

 


 

(图1:Ruby的对象模型)

 

上图中绿色代表”普通“类,蓝色代表meta-class。虚线代表类与对象间的关系(instance of),箭头指向的方向为”类的方向“。实线代表继承关系,箭头指向的方向为“父类”方向。

 

上例中的ExampleClass只是上图中所指的“普通类”Class的一个实例,可以通过下面的方法印证:

 

puts ExampleClass.new.class
puts ExampleClass.class
 

输出:

 

"ExampleClass"
"Class"

 

相对于ExampleClass而言,类Class就是它的meta-class

 

所有的”最低级类“都是类Class的实例?没错。实际上,我们需要注意一点:类名是一个常量 。比如当我们调用ExampleClass.new时,我们实际上是向一个Class类的实例发送消息,而类名这个常量指向的就是这个实例。

 

再来看看,ClassMethodExample类中的类方法,实际上就是这个Class类实例的singleton method,它们也存在于这个实例的singleton class中:

 

puts ClassMethodExample.instance_methods.inspect
puts ClassMethodExample.class.instance_methods.inspect

class << ClassMethodExample
  puts self.instance_methods.inspect
end
 

输出结果:

 

"['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

评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

文章信息

  • andyhu1007在2009-08-08创建
  • andyhu1007在2011-05-26更新
  • 标签: ruby, rails, ruby object model
Global site tag (gtag.js) - Google Analytics