如果想要讓某物件在「發生某事」時通知另一個物件「做某事」,那麼我們會使用 Observer Pattern 來實現。簡單的做法是:
這個做法很單純,但是不夠泛化,Sender 可能不只有一個事件,該事件也不一定只會呼叫 refresh。
class Sender { +__new__() { this.listener = [] } +somethingHappend() { this.listener.each( lambda( l ) { l.refresh( arguments ) } ) } +addListener( that ) { this.listener.append( that ) } -trigger() { this.somethingHappend() } } class Receiver { +__new__() { sender = Sender() sender.addListener( this ) } +refresh() { // blah blah } }當 Sender 的 somethingHappend 執行時,它會通知所有已被 addListener 加入的物件執行 refresh 動作。
這個做法很單純,但是不夠泛化,Sender 可能不只有一個事件,該事件也不一定只會呼叫 refresh。
class Observer { +connect( slot ) { this.listeners.append( slot ) } +__call__() { this.listeners.each( lambda( args, l ) { l( args ) }.bind( arguments ) ) } -listeners = [] }為此我們需要一個統一的介面來操作,class Observer 就此應運而生。
就 connect 而言,我們關心的是事件發出者是誰,它發生什麼事件,事件接收者是誰,它做了什麼事。
稍後我們會處理好事件發出者以及發生什麼事件的辨別方式,因此在這個 Observer 裡只儲存事件接收者和對應的處理函式。slot 即代表被註冊進來的處理函式,儲存起來以備以後使用。
__call__ 這個函式會在事件發生時被呼叫,它做的事很單純,就是呼叫每一個註冊起來的處理函式,並把自己接收到的參數傳給那些處理函式。
當然在這裡最麻煩的就是參數型態及個數,這裡端看各種語言的特性會有不同的實作。基本上動態語言都不會有什麼大問題,但那些靜態語言就需要一些特殊的手法。
使用時就像這樣:
這裡並沒有討論細節,比方說 mutex lock,解除監聽,還有 receiver 反查 sender 的機制。
class Sender() { +somethingHappend = Observer() -trigger() { this.somethingHappend( arguments ) } } class Receiver() { +__new__() { sender = Sender() sender.somethingHappend.connect( this.refresh ) } +refresh() { // blah blah } }可以看到 Sender 本身可以持有數個不同的 Observer,而且不同的 Sender 實體可以各自綁定不同的事件。當 Sender 的 trigger 發出事件通知,Receiver 相對應的處理函式就會被喚起。
這裡並沒有討論細節,比方說 mutex lock,解除監聽,還有 receiver 反查 sender 的機制。
沒有留言:
張貼留言