觀察者模式、事件通知、消息隊列三者有相似,都有回調函數註冊,通知調用的設計,容易混淆。網絡
以上課鈴聲爲例子。上課鈴聲響,同窗們回教室。多線程
class 上課鈴{ function 響() for 學生 in 學生們 do 學生->回教室() end end }
這樣寫有問題:函數
class 學生{ function update() if 上課玲響 then 回教室() end end }
這樣上課鈴只管按時響就好了,也有問題:this
class 上課鈴: Subject{ function 響() NotifyObservers() end } class 學生: Observer{ function init() 上課玲->AddObserver(this.回教室) end function 回教室() ... end function un_init() 上課玲->RemoveObserver(this.回教室) end }
這樣,上課鈴只要響的時候發個通知,學生們就等通知好了。老師也相似,等通知就好了。spa
實際就是註冊個回調函數,完美的將觀察對象和被觀察對象分離。
我的理解:依賴注入,控制反轉。觀察者依賴被觀察者,而不是被觀察者依賴觀察者。線程
觀察者模式有兩個問題:設計
上課鈴的例子裏,學生只關心鈴聲,不關心上課鈴這個物體。
用事件模式就能夠換個寫法code
class 事件系統{ function register(事件類型, handle); function remove(事件類型, handle); function trigger(事件類型, 數據); } class 上課鈴{ function 響() 事件系統->trigger("上課鈴聲") end } class 學生{ function init() 事件系統->register("上課鈴聲", this->回教室) end function 回教室() ... end function un_init() 事件系統->remove("上課鈴聲", this.回教室) end }
事件通知系統用的很普遍的。不少代碼會有個EventDispatcher
、EventControl
之類的類。
特別是UI程序,當數據發生變化時通知相關UI更新。
觀察者模式能夠作到,可是事件通知來實現會更加簡單。server
消息隊列和事件系統很像。可是消息隊列不是當即通知,而是把消息先放到隊列裏再通知。
上課鈴的例子對象
class 消息隊列{ function register(消息類型, handle); function remove(消息類型, handle); function sendMsg(消息); function process(); } class 上課鈴{ function 響() 消息隊列->sendMsg("上課鈴聲") end } class 學生{ function init() 消息隊列->register("上課鈴聲", this->回教室) end function 回教室() ... end function un_init() 消息隊列->remove("上課鈴聲", this.回教室) end } main{ while(有消息) do 消息隊列->process() end }
從僞代碼也能夠看出,消息隊列和事件系統的使用基本是同樣的。若是消息隊列不延後處理,就是事件系統了。
消息隊列能夠用於多線程,接受處理消息的handle們在主線程裏。發送消息的能夠在其餘線程裏。
須要分層解耦就用事件通知系統。 須要時間解耦就用消息隊列