我最近讀了些文章(比如這篇),宣傳在 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
可是我懶得把它們一個個寫出來!
新聞熱點
疑難解答