三种在类中使用模块代码的方法

73 阅读2分钟

上周,我们学到了一些关于单子类的重要知识:类方法是一个类的单子类的实例方法。不过,让我们退一步来说--这与extend

我们已经知道 include将一个模块插入到类的祖先链中,就在该类的后面,includesprepend在它之前插入一个模块。那么,extend 也会将一个模块插入祖先链,但它是在类的单子类(而不是类本身)的祖先链上这样做的。

module ExampleModule ; end

class ExampleClass
  extend ExampleModule
end

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

ExampleClass.singleton_class.ancestors
=> [#<Class:ExampleClass>, ExampleModule, #<Class:Object>,
#<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

#<Class:ExampleClass> 语法意味着它是ExampleClass 的单子类。我们可以看到ExampleModule 被插入到ExampleClass的单子类的祖先链中。

让我们把这与我们所学到的关于单子类的知识结合起来--一个类的单子类的实例方法就是该类的类方法。所以说我们有一个定义在ExampleModule 上的实例方法:

module ExampleModule
  def example_module_instance_method
    "This is an instance method defined on ExampleModule"
  end
end

如果我们在extend ExampleModule ,它就会成为ExampleClass 的一个类方法

class ExampleClass
  extend ExampleModule
end

ExampleClass.example_module_instance_method
=> "This is an instance method defined on ExampleModule"

如果我们在同一个ExampleModule ,而不是使用include ,那么这个方法就仍然是一个实例方法:

class ExampleClass
  include ExampleModule
end

ExampleClass.new.example_module_instance_method
=> "This is an instance method defined on ExampleModule"

很好!我们现在已经学会了三种在类中使用模块代码的方法:

  • include将一个模块插入类的祖先链中,紧随其后。
  • prepend在类的祖先链中插入一个模块,就在类的前面。
  • extend 将模块插入类的单子类的祖先链中,就在类的后面,这意味着基本上所有模块的实例方法都可以像类的方法一样在扩展它的类中被访问。