元编程:对象模型

第一章节的内容是对象模型,相对来说比较简单,本篇文章先直接总结知识点,其实以后再回过头来看本篇文章的时候直接看知识点总结就可以了,除了知识点的罗列之外,重点介绍几个关键性的知识,比如self的使用,方法查找、方法执行、Kernel模块中定义的方法、私有方法调用的方式等。

下面是这个章节的知识点总结:

  1. 对象由一组实例变量和一个类的引用组成
  2. 对象的方法存在于对象所属的类中,从类的角度看,它们叫做实例方法
  3. 类本身是Class类的对象,类的名字不过是一个常量而已
  4. Class类是Module的子类,一个模块基本上是由一组方法组成的包,类除了具有模块的特性之外,还可以被实例化(new)以及被组织为层次结构(superclass)
  5. 常量像文件系统一样,是按照树形结构组织的,其中模块和类的名字扮演目录的角色,其他普通的常量则扮演文件的角色
  6. 每个类都有一个祖先链,这个链从自己所属的类开始,向上直到BasicObject类结束
  7. 当调用一个方法时,Ruby首先向右一步到接受者所属的类,然后一直向上查找祖先链,直到找到该方法,或者到达链的顶端为止
  8. 每当类包含一个模块时,该模块会被插入到祖先链中,位置在该类的正上方
  9. 当调用一个方法时,接收者会扮演self的角色
  10. 当定义一个模块或者类时,该模块扮演self的角色
  11. 实例变量永远被认定为self的实例变量
  12. 任何没有明确指定接受者的方法调用,都当成是调用self的方法。
self的使用

如知识点9、10所示,self的角色通常由最后一个接收到方法调用的对象来充当,不过在类和模块的定义中,并且在任何方法定义之外,self的角色由这个类或模块担任,代码如下所示:

class MyClass
  puts self      #打印结果是MyClass
end

当前对象显示,在类或者模块外面,当前对象是main,代码如下所示:

puts self  #这段代码返回的是main
private的使用

私有(private)方法是实现一个类时使用的内部方法,它只能被这个类(或者它的子类)的实例方法所调用。私有方法只能隐式地被self对象调用,并且不能通过一个对象进行显式调用。如果m是一个私有方法,那么只能用m这种方式来调用它,而不能用obj.m或者self.m来调用它,代码如下所示:

class C
  def public_method
    self.private_method()
  end

  private
  def private_method
  end
end

C.new.public_method  #这段代码会报出NoMethodError
方法查找

规则:向右一步,再向上,先向右一步来到接收者所在的类,然后沿着祖先链向上直到找到给定的办法,代码如下所示:

class MyClass
end

class MySubClass < MyClass
end

puts MySubClass.ancestors #这段代码打印出来的结果是[MySubClass, MyClass, Object, Kernel, BasicObject]

如果类中include模块,代码如下所示:

module Printable
end

module Document
end

class Book
  include Document
  include Printable
end


puts Book.ancestors #这段代码返回的是[Book, Printable, Document, Object, Kernel, BasicObject]
#上面这段代码说明最后include的模块,其方法最先被使用
#假如Document和Printable模块都包含了print方法,Book类的实例调用print方法,最先调用的是模块Printable中的方法

以上的代码说明,后加入的模块刚好在Book类的下面。

方法执行

下面的代码是演示代码执行:

class MyClass
  def testing_self
    my_method  #这段代码的作用和self.my_method一致
  end

  def my_method
    puts "this is my_method"
  end
end

obj = MyClass.new
obj.testing_self  #这段代码返回的是this is my_method

上面代码中testing_self的self是obj,在方法内部中调用my_method,其self也是obj,my_method和self.my_method的作用是一样的。

Kernel方法的调用

Kernel中的方法也被称为Kernel method(内核方法),这个关键知识点也可以见我提出的一个问题,问题内容见链接,问题中的知识点总计已经整理成文章。

Refinement

修改类带来一个问题就是,这种修改是全局性的,解决这个方法的方案是使用refinement,而且只能在模块中进行refine,类中不行。

refinement只在三种场合有效:

  • refine代码块内部
  • 如果是模块中,从using开始到模块结束
  • 如果是顶层上下文中,从using开始到文件结束
#在refine代码块内部有效的代码如下所示:
module StringExtensions
  refine String do
    def to_alphanumeric
      gsub(/[^\w\s]/, '')
    end

    "**first**".to_alphanumeric #=>first
  end
end

在全局中使用refinement
module StringExtensions
  refine String do
    def to_alphanumeric
      gsub(/[^\w\s]/, '')
    end
  end
end

"my *first* refinement!".to_alphanumeric  #undefined method

using StringExtensions
"my *first* refinement!".to_alphanumeric #=>my first refinement

在模块中使用refinement
module StringExtensions
  refine String do
    def reverse
      "cc"
    end
  end
end

module StringStuff
  using StringExtensions
  "my_string".reverse  #=>"cc"
end

"my_string".reverse #=> "gnirts_ym"
测试

1、利用ancestors方法理解类的继承和模块导入原则
2、利用refine方法介绍refinement的三种形式

你可能感兴趣的:(元编程:对象模型)