" Dynamic method is the technique of defining a method at runtime " from Metaprogramming Ruby
可先從 Ruby documentation 找到 define_method 的用法:
define_method(symbol, method) → symbol
define_method(symbol) { block } → symbol
以書中提供的範例來說:define_method 方法只需要提供
(1) 方法名稱
(2) block 裡放要執行程式碼就足夠了。
注意 define_method 是在 MyClass 類別內執行的,所以 my_method() 定義為 MyClass 的實例方法。
這種在 runtime 中定義的方法就被稱為是 Dynamic Method。
class MyClass
define_method :my_method do |my_arg|
my_arg * 3
end
end
obj = MyClass.new
obj.my_method(2) # => 6
嚴格說來,define_method 與我們所熟悉的 def…end 的差別其實不大,最重要的不同是 define_method 允許在 runtime 的環境下,讓你決定方法的名稱。
從以下例子看到 define_method 的好用之處在哪。
class Store
def trade_gold(arg, weight)
"Taipei branch has traded #{arg} for #{weight} kg today"
end
def trade_silver(arg, weight)
"Taipei branch has traded #{arg} for #{weight} kg today"
end
def trade_platinum(arg, weight)
"Taipei branch has traded #{arg} for #{weight} kg today"
end
end
tw_branch = Store.new
tw_branch.trade_gold('gold', 10)
# => "Taipei branch has traded gold for 10 kg so far today"
tw_branch.trade_silver('silver', 22)
# => "Taipei branch has traded silver for 22 kg so far today"
tw_branch.trade_platinum('platinum', 5)
# => "Taipei branch has traded platinum for 5 kg so far today"
有注意到 Store 類別裡的三個方法都蠻相似的,且回傳的內容重複性也蠻高的。
雖然我們也可用傳統的 def…end 來編碼,但要真正地精簡程式碼,可把方法的名稱在同ㄧ個陣列裡,再以『動態方法』來定義:
class Store
["gold", "silver", "platinum"].each do |metal|
define_method("trade_#{metal}") do |arg|
"Taipei branch has traded #{metal} for #{arg} kg so far today
end
end
end
tw_branch = Store.new
tw_branch.trade_gold(10)
# => "Taipei branch has traded gold for 10 kg so far today"
tw_branch.trade_silver(22)
# => "Taipei branch has traded silver for 22 kg so far today"
tw_branch.trade_platinum(5)
# => "Taipei branch has traded platinum for 5 kg so far today"
可以看出我們並沒有改變回傳值,而是將方法名稱放進陣列,不但減少了重複的程式碼,也讓陣列裡的名稱及對應的方法更有彈性。
如此一來,當需要新增、刪除或是修改方法時,只要控制陣列內的元素即可。