l

2017年1月9日 星期一

Observer和Publish-Subscribe

Jan. 09 11:25~14:00

屏幕截图 2017-01-09 13.47.43

▲花生做的豆腐,還算是豆腐嗎?

 

先聽個故事…

工程師甲:我覺得這個地方可以套Observer Pattern。

工程師乙:蛤!Observer Pattern?

工程師甲:對啊,有什麼問題嗎?

工程師乙:我們可是在開發網路應用程式耶,資料發送端和接受端在不同的電腦上,怎麼套用Observer ?

工程師甲:喔,那你就找個Message Queue的開源軟體,可以在分散式環境中支援非同步的Observer Pattern。

工程師乙:Message Queue支援的應該是Publish-Subscribe Pattern吧,怎麼會是Observer Pattern?

工程師甲:這兩個名詞是同義字啊,你看GoF書上293頁有寫:「Observer又稱為Dependents或Publish-Subscribe」。

工程師乙:你不要死讀書、讀死書好不好,現在實務上的做法Observer和Publish-Subscribe老早就不同了,前者是指用同步的方式在同一個memory space裡面一對多的訊息通知,後者是在不同的memory space中以非同步的方式做到一對多或多對多的訊息通知。

***

(工程師甲內心獨白:GoF「聖經」所寫的話你也敢反對!)

工程師甲:在GOF書中並沒有說Observer的實作一定要用同步的方式啊,也沒有規定只能用在同一個memory space。你去看看書中 300頁有提到Subject和Observer之間可以套用ChangeManager,在ChangeManager上面做點手腳就可以實作出你所說的非同步通知且支援一對多或多對多的Observer,也就是你說的Publish-Subscribe。

obser025

▲節錄自《GOF》

 

工程師乙:你這樣說會造成開發者的困擾啦,明明就是兩個不同的Pattern你硬要說這是同一個。如果今天在開發一個分散式系統你跟新人說要套用Observer但實際上你需要的是Publish-Subscribe,而這個新人又不知道這兩者的區別,傻傻地想辦法去做出一個「標準版的Observer」出來,那不是浪費大家的時間。

工程師甲:Observer的實作本來就可以有不同的「變形」啊,不只是Observer幾乎所有的設計模式實作上都有不同的細節,不能因為一些實作細節不同就說它們是不同的模式。

工程師乙:我不管這些變形,現況就是實務上Publish-Subscribe和Observer已經有很清楚的差異了,將這兩者分別開來讓開發人員很容易區隔這樣不是很好嗎。硬說它們是同一個模式,然後再要求開發人員依據不同狀況去區分實作細節,這樣反而容易造成誤會,不會比較好啦。

***

昨天在PTT的Soft_Job看到有人在討論Observer和Publish-Subscribe是否為相同設計模式的問題(討論連結)。贊成者認為GoF書上都這麼說了還能有錯嗎?而且還舉了《設計模式之禪》、《GoF原文中譯》、《品味Java的21種設計模式》、《大話設計模式》、《設計模式》、《深入淺出設計模式》這幾本書中的說法作為佐證(舉了這麼多本書等於只給了一本參考資料,因為其他書應該都是參考《GOF》的講法,自然認為Publish-Subscribe就是Observer)。

反對者認為實務上Publish-Subscribe和Observer就是兩種不同的做法,在現實生活中兩者已經分道揚鑣了,再拿書中的講法硬要說它們是一樣的反而造成誤解。

也有鄉民認為Observer應該是Publish-Subscribe的子集合才對啊,兩者怎麼會相等。也有人覺得「糾結名詞沒有意義」。

***

看到這個討論讓Teddy想起之前在網路上看到的一則新聞,中國某官方單位要求境內媒體不准使用「台語」這種說法,一律要使用「閩南語」,因為這世界上根本沒有「台語」,只有「閩南語」。台灣地區所謂的「台語」就是「閩南語」,就算在一些用語上在台灣地區與閩南地區略有不同,這也只是「實作上的小變形」,不足以讓「台語」脫離「閩南語」單獨成為一個Pattern…不對,是單獨成為一種語言。

看到這則新聞許多台灣人可就不同意了,實務上台語就台語誰跟你閩南語啊。你跟台灣人提到「台語」大家都知道你指的是什麼語言,你提到「閩南語」搞不好造成「新手」的誤解,以為這是什麼奇怪的外國語XD。

扯了這麼多談一下Teddy自己的看法,以下純屬公堂之下大膽假設,沒有什麼科學根據。《GoF》這本書出版已經超過20年了,20年前分散式系統不像今天那麼普及,普及到好像呼吸空氣一樣自然。也就是說在《GoF》出版的那個年代,也許作者認為(非同步、跨memory space)Publish-Subscribe本質上和Observer是相同的,而且前者的使用情況不像Observer那麼普及,所以就把Publish-Subscribe當成Observer的同義字,不需要單獨區分成不同的設計模式,只看成是一種設計模式在實作上的差異即可

隨著時間流轉,《GoF》設計模式應用在多執行緒、分散式系統、行動計算這些環境中的實作方式和原本書中提到的做法已有很大的差異。也許有些差異大到個別獨立成另一個設計模式會比較符合現代的使用情境,甚至獨立之後繼續壯大,反倒回頭「包含」原本的母體也說不定。MSDN上有一個例子,Publish/Subscribe獨立成為一個模式,它的別名為Pub/Sub。文中提到「List-Based Publish/Subscribe可以用Observer pattern」實作。從這個角度來看,Observer 成為Publish-Subscribe的一種實作方式(子集合),而非同義字了。

***

情境(Context)不同,名詞所代表的意義很可能也不同。在英國你說football是「足球」,來了美國football變成美式足球。同一個字有不同的意義,到底誰對誰錯?兩者都對,只是Context不同意義不同而已。再稍微扯遠一的,DDD(Domain-Driven Design)為了避免名稱溝通的問題,提出Bounded-Context的概念:「一個名詞的意義只有在相同的Bounded-Context才有意義」。以上述football的例子,英國和美國各屬於不同的Bounded-Context,相同的名詞有著不同的含意實屬正常現象。

在《GoF》這個Bounded-Context中,Publish-Subscribe是Observer的別名,兩者是同義字。在另一個Bounded-Context,也許是分散式系統,Publish-Subscribe與Observer很可能是兩個不同的設計模式,意義各不相同。

***

友藏內心獨白:把Context說清楚很重要。

沒有留言:

張貼留言