iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 12
0
自我挑戰組

Metaprogramming Ruby and Rails系列 第 12

Day 12 -- Dynamic Methods Part II

Defining Methods Dynamically

" 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

Def…end VS. Define_method

嚴格說來,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"

可以看出我們並沒有改變回傳值,而是將方法名稱放進陣列,不但減少了重複的程式碼,也讓陣列裡的名稱及對應的方法更有彈性。

如此一來,當需要新增、刪除或是修改方法時,只要控制陣列內的元素即可。


上一篇
Day 11 -- Dynamic Methods Part I
下一篇
Day 13 -- Method Missing In Ruby
系列文
Metaprogramming Ruby and Rails33

尚未有邦友留言

立即登入留言