如果想要讓某物件在「發生某事」時通知另一個物件「做某事」,那麼我們會使用 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 的機制。
沒有留言:
張貼留言