Ruby Object 类详细分析(2)

来源:互联网 发布:官方淘宝波司登羽绒服 编辑:程序博客网 时间:2024/06/08 03:54
 

2.       动态性

动态性是Ruby的灵魂。Ruby的动态性体现在很多方面,Object类中也有一个最根本的体现,就是send方法,由于这个方法如此重要,为了使得在这个方法被覆盖时你可以同样获得这种功能,Object还提供了一个__send__方法,它们完成同样的功能。

class SayHello
   def hello(name)
         puts "hello, #{name}."
   end
end

sayHello = SayHello.new

sayHello.send("hello", "Bob")       #=>"hello, Bob."
sayHello.__send__("hello", "Bob")   #=>"hello, Bob."

很显然,通过调用send方法,我们可以获得和调用hello方法一样的能力。但是,它更强大,send方法是动态的,就是说,我们可以动态调用任何存在的方法。你大概联想到C语言中的函数指针了吧,或者你联想到Java.Net世界中的反射了吧。Ruby要简洁得多,不是么?而且,你甚至还可以调用不存在的方法!你如果使用过Rails,一定会好奇Rails的模型中的find方法族吧,你不光可以调用find方法,你还可以调用findBy[Column_Name]来根据你模型中的一列或若干列来进行查找,而你根本没有定义过这些方法!

魔法的秘密在于method_missing,这个方法会在当send方法找不到传入的方法名时被调用,在Object对象中,这个方法会抛出一个NoMethodError的错误,但是,你可以利用它来搞一些诡计,比如我们想在上面的类中实现可以调用hello_[Name]方法来对给定的人说“hello”。

class SayHello
  def hello(name)
    puts "hello, #{name}."
  end
 
  alias old_method_missing method_missing
  def method_missing(method_id)
    if match = /hello_([a-zA-Z]/w*)/.match(method_id.to_s)
      hello(match.captures.to_s)
    else
      old_method_missing(method_id)
    end
  end
end

sayHello = SayHello.new

sayHello.send("hello", "Bob")       #=>"hello, Bob."
sayHello.send("hello_Bob")          #=>"hello, Bob."
sayHello.hello_Bob                  #=>"hello, Bob."
sayHello.wrongMethod                #=>NoMethodError occurs.

当然,这里的例子相对还是比较简单,比如只支持一个名字,你显然可以用自己的方式把它定义的更加像样。RailsActiveRecord::Base类使用了相似的技术来实现那些魔术般的find方法族,只是更加复杂些。

原创粉丝点击