發佈/訂閱模式 vs 觀察者模式

觀察者模式 (Observer Pattern)發佈/訂閱 (Publish/Subscribe, Pub/Sub) 都描述「狀態或事件改變後通知關心它的人」,但不是可任意互換的同義詞。
 
GoF 的 Observer(也稱 Dependents)通常是 Subject 直接持有 Observer reference 的物件互動;現代語境的 Pub/Sub 常指 topic、broker 或 event bus 上的訊息模式。它們可以互相借鏡,卻應先把拓撲、時間與投遞語意說清楚。
 
然而,目前實務開發的背景中,
Pub/Sub 更廣泛地被指為:

用於建立一些 事件驅動 (Event-driven)訊息傳遞協議訊息導向中介軟體(MOM)
(e.g., MQTT、XMPP、SNS、JMS) 之訊息模式。

 
subscribe
 


 

模組的解耦

許多 發佈/訂閱 系統,
會在 發布者 (Publisher)訂閱者 (Subscriber) 之間,
透過 中間人 (broker) 或 Message/Event Bus… 來進行解耦。
 
使得 發佈者 與 訂閱者 彼此並不認識,
就像訂閱某個粉專,訂閱者 不需知道 發文的小編 是誰。
pub-sub
 


 

時間的解耦

訊息傳遞,可以是 同步 (synchronous)非同步/異步 (asynchronous)
(以下簡稱 sync 與 async)
在這 [註1] 也稱為 等待 (blocking) 或 非等待 (non-blocking)。

 
快遞送貨到某處,結果對方家裏沒人,若快遞癡癡地等… 他就完了,
其他貨都不用送了膩?
 
同理:

發佈訊息時,訂閱者 (Subscriber) 不一定會在線上

 
許多 Pub/Sub 實作採 async,使發布者不必等待訂閱者處理訊息,達到時間上的解耦;但 async、non-blocking、durable 與 reliable 是不同維度。是否先存再送、離線訂閱者能否補收、是否至少一次/至多一次/恰好一次投遞,都取決於 broker、QoS、ack、重試與持久化設定,不能僅憑 Pub/Sub 保證可靠送達。
 
[註1]: 兩者並不一定相同
 


 

再談觀察者模式

GoF 原著提到:

觀察者模式 (Observer Pattern)
可利用 『ChangeManager』封裝起複雜的更新語意,
藉此將 Subject 與 Observer 解耦,
並且,可將 ChangeManager 寫成 單例模式 (Singleton Pattern) 來使用。

 
ChangeManager
 
Singleton 的意義是限制同一個執行行程中的實例數量;它不會自然跨行程、跨主機或跨平台。若要把 ChangeManager 延伸成分散式訊息傳遞,仍須明確加入 IPC、網路協定、broker、序列化與失敗處理。
 

你或許會認為與 Pub/Sub 頗為相似? 或根本一樣?

 


 

Pub/Sub vs. Observer Pattern

有些人說 Observer Pattern 是 一對多sync
而 Pub/Sub Pattern 是 多對多async
 
事實上,GoF 從來沒有規範
觀察者模式 (Observer Pattern) 需使用 sync,
也沒有說 Subject 不行進行擴充,
 
因此你可以看到,我撰寫的觀察者模式實作介紹中
訂閱了多個 Subject,且提醒你可以使用異步方式。
 
MQTT 的 官方文件中,則提到:

Use of the publish/subscribe message pattern
which provides one-to-many message distribution and decoupling of applications.

 
發布/訂閱 模式,提供了『一對多』的消息分佈。

Pub/Sub 並沒有『多對多』的這項規範。

 
Observer Pattern 指的『一對多』,是指單一抽象觀念的兩個層面,
並非指只能有一個具體 Subject!
 
常見的企業或分散式 Pub/Sub 會有 broker 並採 async,但這不是定義必要條件:in-process event bus 可以同步,brokerless Pub/Sub 也存在。真正需要寫清楚的是拓撲、訂閱模型、投遞保證、順序、保留與失敗處理。
 


 

總結

許多文件中,更常可以看到的是『mechanism』這個字眼,
發佈/訂閱 描述為一種機制或概念,
並拿來與其他訊息傳送機制做比較,如: 點對點 (point-to-point)。
 
在不同的時空背景、程式語言、使用需求,意義或許不盡相同,
有些認為 Publish/Subscribe 是 Observer 的實作面,
有些人認為他們截然不同。
 
如 XMPP 的 官方文件中
提到:

Pubsub therefore adheres to the classic Observer design pattern
and can serve as the foundation for a wide variety of applications

 
發布/訂閱 模式,遵循了經典的 觀察者設計模式
因此可作為各種應用的基礎。
 
其 RFC6121文件,也說明了:
XMPP 其存在基礎,是遵循著 Observer 或 Publish/Subscribe Pattern。
 
我會把它們視為共享事件通知精神、但常用來描述不同設計層次的名詞:Observer 著重物件間的直接依賴;Pub/Sub 常著重訊息主題與傳遞拓撲。實作前先寫清楚語境,比爭論誰是誰的別名更有用。
 
就如 泰迪軟體科技 創辦人 — Teddy Chen,
於其 Observer和Publish-Subscribe 一文中所述:

一個名詞的意義,只有在相同的 Bounded-Context 才有意義。

 
良葛格也說過:
技術名詞紛爭多

使用某個模式概念,
針對實際處理的問題實作出來的方案,
必然會有不同的調整與結果。

 
名詞是拿來溝通,不是拿來裝逼的,
理解其原理精髓,並因應需求來實作、調整和修改才最重要 😀。
 
總之
dispute
 
 

作者: 鄭中勝
喜愛音樂,但不知為何總在打程式 ? 期許能重新審視、整理自身所學,幫助有需要的人。

發表迴響