iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 13
0
Software Development

Ruby 研究 30 天系列 第 13

Day 12 - 事件觸發 ( EventEmitter )

EventEmitter

今天我想用一個 Codewars 的題目來練練上一章的所學,題目及說明在以下程式碼裡:

class EventEmitter
  # your code
end

evt = EventEmitter.new

# 無註冊事件(未使用 on 方法直接 trigger)
evt.trigger('marry_him')            # 無任何輸出

# 註冊一個事件
evt.on('marry_me') { puts '好'}
evt.trigger('marry_me')             # 印出 好

# 重複註冊事件
evt.on('ithome') { puts '鐵人賽'}
evt.on('ithome') { puts '一天一篇'}
evt.on('ithome') { puts 'hold 住!'}
evt.trigger('ithome')               # 印出 鐵人賽 一天一篇  hold 住!

這題的目的是要利用 on 這個方法將後面的 block 內容儲存起來,用 trigger 方法來印出儲存的內容。

分析一下題目,因為已經將 block 接在方法後面,所以沒辦法用前一天提到的 Proc way 直接將 block 變成物件再當做參數傳進去存起來,若直接用 yield way 則是會直接執行 block 的內容而不能儲存,所以這裡用 & 方法來試試。

class EventEmitter
  def initialize
    @event = Hash.new{|hash, key| hash[key] = [] }
  end

  def on(str, & block)
    @event[str] << block
  end

  def trigger(str)
    @event[str].each{ |block| block.call }
  end
end
  1. 這裡我定義一個 hash 並將之指向名為 @event 的實體變數,將「事件」作為 key ,它的 value 是一個空陣列用來裝所有 block
  2. 為了讓 block 可以當作參數傳入方法中,這裡加上 & ,因此我的@event 會長得像這樣 { :str => [ block_1, block_2, block_3 ]}
  3. 最後在 trigger 方法中將每個物件化後的 block 用 call 方法一個一個呼叫。

當然解決事情的方法一定不會只有一種,下面我們用 yield + proc 寫寫看:

class EventEmitter
  def initialize
    @event = Hash.new{|hash, key| hash[key] = [] }
  end

  def on(str)
    @event[str] << Proc.new{ yield }
  end

  def trigger(str)
    @event[str].each{ |block| block.call }
  end
end

這裡的差別在於,上一章有提到 yield 就是將 block 的{} 扒掉,因此我在外面又包一個花括號將它還原回 block ,接著用 Proc.new 將之物件化,後續是一樣的,只是在轉換過程中,這裡的範例我會覺得用 & 比較直觀些。

此文同步刊登於CJ-Han的網站


上一篇
Day 11 - Block
下一篇
Day 13 - 類別變數與實體變數
系列文
Ruby 研究 30 天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言