Inside Ruby: Object Model

今天来重新了解一下ruby的Object Model,之所以是重新,因为是从内部来看,而不是从外部的使用上。

1. object object = instance variables + methods(包括一个指向所属class的方法)。使用object.instance_variables 和object.methods可以查看对应的信息, 区别在于前者存在于object本身,而method存在于object的class中,这些method在class中被称作instance method,这也是为什么同一个class不同object可以共享方法,但是不能共享instance variable。

2. class class也是一个object,是Class的实例,拥有instance methods和指向父类的方法superclass。Class是Module的子类,所以一个class也是一个module。

3. module module与class没有根本差别,因为class本身就是module的子类,但是引入module与class的目的是不同的。通常来说,class用来实例化和继承,而module用来mix in或者作为namespace。 下面的代码片段展示了部分上述内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass
  def my_method
    @v = 'instance variable'
  end
end

obj = MyClass.new
obj.instance_variables    # => []
obj.my_method
obj.instance_variables    # => [:@v]
obj.methods == MyClass.instance_methods    # => true
MyClass.class        # => Class
Class.superclass     # => Module
Module.superclass    # => Object
MyClass.superclass   # => Object

4. include

先看下面的代码

1
2
3
4
5
6
7
8
9
10
11
module A; end
module B; end

class BaseClass; end
class MyClass < BaseClass
  include A
  include B
end

MyClass.ancestors   # => [MyClass, B, A, BaseClass, Object, Kernel, BasicObject]
MyClass.superclass  # => BaseClass

在面向对象的语言中,当我们调用方法的时候,首先会在当前类中寻找,如果找不到,则会去父类中,然后是父类的父类。Ruby中提供了一个superclass方法,顾名思义是返回父类,但是Ruby并不是按照superclass的返回结果层层向上寻找方法。与Java和C#一样,Ruby不允许多继承,但是Module的引入使得它有所不同,不同在于,Ruby是按照ancestors的返回结果来寻找,这个ancestor tree中包含了class和module。

所以,Ruby查找方法的顺序为:当前类 -> include的module的逆序,-> 继承的父类。原因在于 ,Ruby中,当在一个class中include一个module时,它会创建一个匿名类,包装那个module,并且将这个匿名类插入祖先树中,仅仅在当前类之上。而superclass对此一无所知。

《Metaprogramming Ruby》一书对这些有非常详细的解释,推荐参考。

comments powered by Disqus