Ruby中的钩子方法详解

2019-09-25 09:41:20于丽


module Person
  def name
    "My name belongs to Person"
  end
end

class User
  include Person
  def name
    "My name belongs to User"
  end
end

puts User.new.name
=> My name belongs to User

现在再来看看 prepend 的情况:


module Person
  def name
    "My name belongs to Person"
  end
end

class User
  prepend Person
  def name
    "My name belongs to User"
  end
end

puts User.new.name
=> My name belongs to Person

使用 prepend Person 会将 User 中的同名方法给覆盖掉,因此在终端输出的结果为 My name belongs to Person。 prepend 实际上是将方法添加到方法链的前端。在调用 User 类内定义的 name 方法时,会调用 super 从而调用 Person 模块的 name。

与 prepend 对应的回调名为(你应该猜到了) prepended。当一个模块被预置到另一个模块/类中时它会被调用。 我们来看下效果。更新 Person 模块的定义:

module Person
  def self.prepended(base)
    puts "#{self} prepended to #{base}"
  end

  def name
    "My name belongs to Person"
  end
end

你再运行这段代码应该会看到如下结果:


Person prepended to User
My name belongs to Person

prepend 的引入是为了去除 alias_method_chain hack的丑陋,它曾被Rails以及其他库广泛地使用以达到与 prepend 相同的功能。 因为 prepend 只有在 Ruby >= 2.0 的版本中才能使用,因此如果你打算使用 prepend 的话,那么你就应该升级你的Ruby版本。

inherited

继承是面向对象中一个最重要的概念。Ruby是一门面向对象的编程语言,并且提供了从基/父类继承一个子类的功能。 我们来看一个简单的例子:

class Person
  def name
     "My name is Person"
  end
end

class User < Person
end

puts User.new.name # => My name is Person

我们创建了一个 Person 类和一个子类 User。在 Person 中定义的方法也成为了 User 的一部分。 这是非常简单的继承。你可能会好奇,是否有什么方法可以在一个类被其他类继承时收到通知呢? 是的,Ruby有一个名为 inherited 的钩子可以实现。我们再看看这个例子:


class Person
  def self.inherited(child_class)
    puts "#{child_class} inherits #{self}"
  end

  def name
    "My name is Person"
  end
end