Ruby 中的对象模型 ( object model ) ( 上 )

yufei       5 年, 8 月 前       1552

都说 Ruby 是一个完全面向对象的编程语言,但,你知道这是什么意思吗 ? 在写下文字的这一刹那,笔者也是迷茫的。 不过没关系,我们可以慢慢学,慢慢的去了解 Ruby 中的对象模型 ( object model )

祖先链 ( Ancestor Chain )

Ruby 面向对象中最重要的一环,就是 ancestors 方法,该方法没有任何参数,但会返回一个数组 ( Array ),这个数组里存储着该类 ( 对象 ) 的所有祖先链 ( 继承链上的所有类 )

「 祖先链 」是 Ruby 类层次结构的表现形式。按顺序,它包含了

  1. 当前被调用的类
  2. 调用的类所处在的模块
  3. 它的父类
  4. 它的父类所处在的模块
  5. 它父类的父类
  6. ... 以此类推

下面的代码显示了 Array 这个类的祖先链

irb> Array.ancestors                   # Array's ancestor chain
 => [Array, Enumerable, Object, Kernel, BasicObject]
irb> Array.included_modules            # Array included modules
 => [Enumerable, Kernel]
irb> Array.superclass                  # the parent class
 => Object
irb> Array.superclass.included_modules # parent's included modules
 => [Kernel]
irb> Array.superclass.superclass       # the grandparent class
=> BasicObject

Array::included_modules 返回一个数组 ( Array ) ,包含了祖先链中包含的所有模块,这也是为什么 Kernel 模块包含在 Array.included_modules 数组中的原因

祖先链和方法调用

当我们在对象内部调用某个方法时,Ruby 做的第一件事就是要确定你所调用的方法是否是存在于 self 上下文中 ( 也就是当前类是否有定义 )

如果没找到,它就会按照祖先链的顺序逐一找寻,知道找到为止。

下面的代码演示了这个查找过程

class Tiger
  def to_s
    "roar"
  end
end

irb> Tiger.new.to_s
 => "roar" # calls the #to_s method defined in the Tiger class
irb> Tiger.inspect
 => "#<Tiger:0x007f>" # calls the #inspect method defined in Object
 ```

 ## 对象类层次结构 ( Object class hierarchy ) 

 `Object` 类是 Ruby 中所有类的默认父类。这句话的所代表的意思是,任何新创建的类默认都从 `Object` 类继承。

```ruby
class Child
end

Child.superclass
 => Object

那么,你也许会问,这个类的目的是什么 ?

有一个非常有意思的是,如果我们在 Object 上调用 ancestors 方法,它仍然会返回 Object 的祖先链

irb> Object.ancestors
 => [Object, Kernel, BasicObject]

也就是说 Object 还有自己的祖先链,它根本就不是那个最顶级的类 ?

BaseObject

BaseObject 是 Ruby 中所有类的最顶级的类。它只包含仅有的两个方法:对象创建和对象比较。

Kernel

Kernel 也包含在 Object 类中,它包含了所有的 「 对象操作 」 逻辑。

Object

由于 Kernel 模块包含了大多数方法,因此 Object 类更多的是作为它所有子类的一个接口 ( 得益于它的类名)。

main 对象

当一个新的 Ruby 程序启动时,Ruby 会自动创建一个 main 对象,它是 Object 类的一个实例。

main 对象是任意 Ruby 程序的顶级上下文,看起来这好像是对 C 的一种认可,因为 main() 函数是所有 C 语言程序的第一入口,Matz 喜欢 C

irb> self
 => main
irb> self.class
 => Object

main 也是任意 Ruby 程序的顶级作用域,这意味着类/模块范围之外的任何指令都在 main 上下文中执行

irb> puts "main context"
 => main context

上面的代码中,puts 方法指的是私有的 Kernel#puts 方法,我们可以访问该方法,是因为 main 方法是 Object 的一个实例,该方法定义在 Kernel 模块中。

现在,让我们明确的尝试通过 self 访问 puts 方法 ( self 指的是 main 对象实例 )

irb> self.puts "main context"
NoMethodError: private method `puts' called for main:Object

报错了,发生的原因是无法使用 接收器 调用私有方法 ( 在本例中为 self )

调用 self.puts 就像调用 main.puts 一样,因此上面的代码,就是尝试在类上下文之外调用 puts

换句话说,我们尝试将私有方法当作公共方法来调用。

结束语

Ruby 是一种完全面向对象的语言,因为从入口点( main 上下文)到程序结束,你将至少在都处在 main 对象的作用域之内

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.