Design Pattern(2) - Observer
April 12, 2017以下文章是閱讀 深入淺出Design Pattern 還有 聖經還有Source making的筆記 圖片截圖自lynda.com的Foundations of Programming: Design Patterns 要更深入的理解一定要去看這兩本書
目的
定義一對多的依存關係 當物件狀態一有變動 就自動通知相依物件做該做的更新動作
現實生活的例子就像是你訂報紙 當有新報紙出來的時候就會送給所有有訂閱的人一份
書上的例子是有一個中央氣象局會有許多天氣的資料 有三個不同的氣象顯示器(目前狀況, 統計資料, 天氣預報)跟中央氣象局subscribe資料 只要中央氣象局有更新 就會通知所有的氣象顯示器
如果你寫程式用過framework, Observer就是MVC裡面的View
結構
-
Subject(Interface): 提供增加/刪除Observer的interface 任何數量的observer都可以訂閱此Subject
-
Observer(Interface): 提供自我更新的介面 Subject變化的時候 自己也跟著變
-
ConcreteSubject(中央氣象局): 知道目前的狀態 狀態有變化的時候通知所有observer
-
ConcreteObserver(氣象顯示器): 實作update 要讓現在狀態跟subject同步 而且還帶有指向ConcreteSubject的reference
優點
-
可以讓你單獨改變Subject或Observer 不會影響對方
-
Subject不關心有多少用戶 他唯一要做的事就是跟observer說一聲哈囉我的狀態變化囉 至於observer要做什麼事不關我的事 observer可以變化可以不變化
缺點
-
改變一個subject可能造成的後果Subject並不知道 比如說某個state的值overflow了 某些observer可能有處理這種case 有些可能沒有 code會不好maintain
-
如果只是單純的跟observer說 哈囉我變囉 Observer需要花費時間精力自行推理是什麼東西變了
實作細節
1.通常一個observer不會只訂閱一個subject 它通常會一次訂閱好幾個 所以update這個function必須更general一點 比如把subject當作argument傳給update
2.如果一個subject要被刪除了 他必須告訴所有的observer說 安安別等我囉 這樣observer那邊可以把subject的reference刪掉
3.實作上 你可以選擇讓subject廣播多一點資訊或是少一點資訊 最極端的就是兩種模式 push跟pull
push就是不管這個observer感不感興趣 我都把所有資料給你 你拿你需要的資料 更新你自己
pull就是我只跟所有observer說我改了 你需要什麼資料 自己來看我改了什麼
4.根據第三點的延伸 其實可以extend subject的interface 讓不同observer只登記他感興趣的更新(比如說中央氣象台有三個update: updateTemperature, updateHumidity 跟updatePressure)
5.封裝複雜的更新: 比如說某個事件發生了 他會更新多個subject 如果每個subject都call update, 那同時訂閱這多個subject的observer就會被叫很多次 很不方便
所以當有改變的時候 先把所有要notify的observer記錄起來 所有subject的所有observer都記起來後再一次notify
DP rule#4 盡量讓需要互動的物件之間關係鬆綁(loosely coupled)
loosely coupled意思是說兩者之間可以互動 但並不需要知道太多彼此的細節
在這個case裡 以Subject來說 Subject只知道所有的observer實作了Observer介面 我連你是什麼class都不需要知道 更不用說實作細節
以Observer來說 任何時候都可以新增observer(包括run-time) 而且有新的observer出現時 subject完全不用更動 只要subject好好maintain observer lists
loose coupling 讓物件跟物件的依賴關係最小化 我們就可以建造更有彈性(容易應付變化)的系統