TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)

2009年8月20日 星期四

Overview of Observer Pattern

如果想要讓某物件在「發生某事」時通知另一個物件「做某事」,那麼我們會使用 Observer Pattern 來實現。簡單的做法是:
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__ 這個函式會在事件發生時被呼叫,它做的事很單純,就是呼叫每一個註冊起來的處理函式,並把自己接收到的參數傳給那些處理函式。
當然在這裡最麻煩的就是參數型態及個數,這裡端看各種語言的特性會有不同的實作。基本上動態語言都不會有什麼大問題,但那些靜態語言就需要一些特殊的手法。
使用時就像這樣:
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 的機制。

沒有留言:

張貼留言