首页 > 学院 > 开发设计 > 正文

Ruby元编程之梦中情人method_missing方法详解

2019-10-26 19:26:59
字体:
来源:转载
供稿:网友

我最近读了些文章(比如这篇),宣传在 Ruby 里使用 method_missing 的。

很多人都与 method_missing 干柴烈火,但在并没有小心处理彼此之间的关系。所以,我想来探讨一下这个问题:

** 我该怎么用 method_missing **

什么时候该抵挡 method_missing 的诱惑

首先,永远不要在还没花时间考虑你用得够不够好之前,就向 method_missing 的魅力屈服。你知道,在日常生活中,很少会让你以为的那样亟需 method_missing:

日常:方法代理

案例:我需要让这个类能够使用另一个类的方法

这是我所见过最普遍的使用 method_missing 的情况。这在 gems 与 Rails 插件里头尤其流行。它的模型类似这样:
代码如下:
class A
  def hi
    puts "Hi from #{self.class}"
  end
end

class B
  def initialize
    @b = A.new
  end

  def method_missing(method_name, *args, &block)
    @b.send(method_name, *args, &block)
  end
end

A.new.hi #=> Hi from A
B.new.hi #=> Hi from A

如此,B 就拥有了 A 的所有实例方法。但是让我们想想,在调用 @b.hi 的时候都发生了什么。你的 ruby 环境沿着继承链一路找 hi 这个方法,到最后,恰恰在丢出个 NoMethodError 前,它调了 method_missing 这个方法。

在上例中,情况并不坏,毕竟这里就两个微不足道的类需要查。但通常,我们是在 Rails 或者其他一些框架的上下文中编程。而你的 Rails 模型继承自 ActiveRecord,而它又集成自其他一大坨的类,于是现在你就有了一坨高高的堆栈要爬⋯⋯ 在你每次调用 @b.hi 的时候!

你的好基友:define_method

估计现在你在抱怨,“但是史蒂夫,我需要 method_missing” 我告诉你,别忘了其实除了情妇之外,你还有个忠诚的好基友,叫做 define_method。

它允许你动态地定义一个方法(顾名思义)。它的伟大之处在于,在它执行过之后(通常在你的类们加载之后),这些方法就存在你的类中了,简单直接。在你创建这些方法的时候,也没有什么继承链需要爬。

define_method 很有爱很可靠,并且能够满足你的日常生活。不信我?接着看⋯⋯
代码如下:
class B
  define_method(:hi) do
    @b.hi
  end
end

“可是我有一大坨方法要定义!” 你抱怨

“没问题!” 我卖萌眨眼
代码如下:
class B
  [:hi, :bye, :achoo, :gesundheit].each do |name|
    define_method(name) do
      @b.send(name)
    end
  end
end

可是我懒得把它们一个个写出来!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表