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)
顯示具有 Design_Pattern 標籤的文章。 顯示所有文章
顯示具有 Design_Pattern 標籤的文章。 顯示所有文章

2011年4月1日 星期五

Another Observer Pattern implementation in Java

由於實在不喜歡 Swing 的 listener 方式,因此我嘗試使用 Java 內建的 Observer 和 Observable 來套用 Observer Pattern,但它比我想像中地還不靈活,原因有三:
  1. 必須要呼叫 Observable.setChanged 才會讓 Observable.notifyObservers 生效,而 Observable.setChanged 是 protected,這意味著你至少必須繼承 Observable 類別,這對於不允許多重繼承的 Java 來說很要命,因為 host class 很有可能來自另一繼承體系。
  2. 你沒辦法透過 composition 繞過這個限制,因為 Observer.update 帶有一個型態為 Observable 的參數,語義上這個參數必須要是發出事件的物件,但若是使用 composition 持有 Observable 物件,Observer 收到的參數就會跟真正發出事件的物件無關,這會破壞這組範式的假設。
  3. 你有可能需要在同一個類別裡發送不同的事件,但使用繼承的做法你只能使用一種通知。如果要達到分派不同事件的目的,就必須要在那唯一的一個 Object 參數上作手腳。

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 的機制。