钩子方法:当执行或者调用某个方法的时候,和这个方法相关联的方法会被执行

钩子方法在被定义的时候必须被定义为类方法。

def self.hooked
  puts "hello world"
end

钩子方法的两种形式:模块中和类中

#模块中需要被定义为模块方法
module Demo
  def inherited(child)
    puts "hello world"
  end
end

class Father
  extend Demo
end

class Son < Father
end

#类中定义为类方法
class Father
  def self.inherited(child)
    puts "hello world"
  end
end

class Son < Father
end

下面介绍元编程书中讲述的几种hook方法,分别是分别介绍

#included, extended, prepended, inherited;
#method_added, method_removed, method_undefined;
#singleton_method_added, singleton_method_removed, singleton_method_undefined;
#included形式
module M
  def self.included(othermod)
    puts "#{self} was mixed into #{othermod}"
  end
end

class C
  include M  #=> M was mixed into C
end

#extended形式
module A
  def self.extended(mod)
    puts "#{self} extended in #{mod}"
  end

  def demo
    return "this is the demo"
  end
end

module Enumerable
  extend A
end
Enumerable.demo #this is the demo

#prepended形式
module Demo
  def self.prepended(mod)
    puts "#{self} and #{mod}"
  end

  def one
    puts "this is the one method in demo"
  end
end

class Prepend
  prepend Demo #Demo and Prepend
end
Prepend.new.one

#inherited
class Father
  def self.inherited(child)
    puts "#{self} and #{child}"
  end
end

class Son < Father
end  #Father and Son
#method_added, method_removed, method_undefined
class Simulate
  def self.method_added(method)
    puts "#{self} and #{method}"
  end

  def self.method_removed(method)
    puts "#{self} and #{method}"
  end

  def self.method_undefined(method)
    puts "#{self} and #{method}"
  end

  def one; end #trigger method_added
  def two; end #trigger method_added

  remove_method :one #trigger method_removed
  undef_method :two #trigger method_undefined
end

#比较undef_method和remove_method方法
undef_method: 删除所有的方法,包括继承来的方法
remove_method: 删除自己的方法,但是保留继承来的方法
#singleton_method_added, singleton_method_removed, singleton_method_undefined
class Simulate
  def self.singleton_method_added(method)
    puts "#{self} and #{method}"
  end

  def self.singleton_method_removed(method)
    puts "#{self} and #{method}"
  end

  def self.singleton_method_undefined(method)
    puts "#{self} and #{method}"
  end

  def self.hello; end

  class << self
    remove_method(:hello)
  end

  def self.hello; end

  class << self
    undef_method(:hello)
  end
end
#result
Simulate and singleton_method_added
Simulate and singleton_method_removed
Simulate and singleton_method_undefined
Simulate and hello
Simulate and hello
Simulate and hello
Simulate and hello

注意点:
1.singleton_method_added会回调自己
2.必须在单例类中执行remove_method和undef_method方法

钩子方法include方法和extend方法的应用

#类扩展:在该类的eigenclass中include模块,使得模块中的实例方法成为类的类方法。
module M
  def demo_method
    puts "this is the demo method in module"
  end
end

class DemoClass
  extend M
end

DemoClass.demo_method #=> this is the demo method in module
#类扩展混入:钩子方法和类扩展结合。
- 定义一个模块,比如MyMixin
- 在MyMixin中定义一个内部模块,这些方法最终会成为类方法。
- 覆写MyMixin#included()方法来用ClassMethods扩展包含者(使用extend()方法)

module MyMixin
  def self.included(base)
    base.extend(ClassMethods)
    #Object#extend()只是接受者eigenclass中包含模块的快捷方式。
  end

  module ClassMethods
    def demo_method
      puts "this is the method in the module"
    end
  end
end

class DemoClass
  include MyMixin
end

DemoClass.demo_method #=> this is the method in the module

#如果不需要为包含着提供实例方法,可以没有必要提供内部模块,直接在MyMixin中定义方法即可,这个方法会成为被包含着的类方法:
module MyMixin
  def self.included(base)
    base.extend(self)
  end

  def demo_method
    puts "this is the method in the module"
  end
end

class DemoClass
  include MyMixin
end

DemoClass.demo_method #=> this is the method in the module

注意的问题

1.钩子方法都需要被定义为单例方法

2.钩子方法的参数是方法名,而不是类名,通过self获取类的信息

3.不要调用钩子方法相关的三个方法:

extend_object, append_features, prepend_features

比如在include方法执行的时候,在included钩子方法被执行之前,模块的append_features方法会被调用并执行具体的include操作。但是推荐的用法是定义included钩子方法。

results matching ""

    No results matching ""