本章介紹 OBSERVER 模式——一種讓物件在狀態改變時自動通知所有依賴者的設計模式。作者從數位時鐘的例子出發,逐步演化出多種 Observer 的實作方式,最後展示 C# 中 delegate/event 的原生支援。
動機:數位時鐘問題#

Figure 32.1: Clock object
- 需要一個
DigitalClock顯示時間,時間來源是TimeSource - 問題:
TimeSource不應該知道DigitalClock的存在——它可能有多種顯示器

Figure 32.2: Testing the DigitalClock
逐步演化#
使用 ClockDriver 解耦#

Figure 32.3: Getting the TimeSource to update the ClockDriver
- 引入
ClockDriver作為中間協調者:TimeSource通知ClockDriver,ClockDriver更新TimeSink(顯示器) TimeSink是一個介面,DigitalClock實作它TimeSource也是一個介面,具體的時間提供者實作它
處理多個觀察者#

Figure 32.6: Handling multiple TimeSink objects
- 當有多個
TimeSink時,ClockDriver需要維護一個觀察者列表 - 每當
TimeSource發出通知,ClockDriver遍歷列表通知所有TimeSink
將註冊機制內建到 Subject#

Figure 32.7: Moving registration and update into TimeSource
- 觀察者的註冊(Register)與通知(Notify)邏輯可以移入
Subject基底類別 - 這就是典型的 Observer 模式:
Subject維護觀察者列表,狀態改變時呼叫Notify()
Pull Model vs. Push Model#

Figure 32.12: Canonical pull-model Observer
Pull Model(拉取模型)#
- Observer 收到通知後,主動向 Subject 查詢所需的資料
- 優點:Observer 只取用它需要的資料
- 缺點:可能需要多次查詢,效率較低

Figure 32.13: Push-model Observer
Push Model(推送模型)#
- Subject 在通知時主動將資料傳遞給 Observer
- 優點:效率高,一次傳遞所有需要的資料
- 缺點:Subject 需要知道 Observer 需要什麼資料,耦合度較高
C# 的 Delegate 與 Event#

Figure 32.8: Using multiple inheritance in C++ to separate Clock from

Figure 32.9: Observer delegation hack in C#
- C# 提供了語言層級的 Observer 支援:delegate 與 event
- delegate 是型別安全的函式指標,可以持有多個方法的參考(multicast)
- event 是 delegate 的封裝,限制只有宣告者可以觸發
public delegate void TimeChangedHandler(int hours, int minutes, int seconds);
public class TimeSource
{
public event TimeChangedHandler TimeChanged;
protected void OnTimeChanged(int h, int m, int s)
{
TimeChanged?.Invoke(h, m, s);
}
}
public class DigitalClock
{
public void Register(TimeSource source)
{
source.TimeChanged += OnTimeChanged;
}
private void OnTimeChanged(int hours, int minutes, int seconds)
{
// 更新顯示
}
}sequenceDiagram
participant TS as TimeSource
participant DC as DigitalClock
participant AC as AnalogClock
Note over DC,AC: 註冊 event
DC->>TS: TimeChanged += OnTimeChanged
AC->>TS: TimeChanged += OnTimeChanged
Note over TS: 時間改變
TS->>DC: OnTimeChanged(h, m, s)
TS->>AC: OnTimeChanged(h, m, s)技巧: C# 的 delegate/event 機制讓 Observer 模式的實作極為簡潔——不需要定義 Observer 介面、不需要維護觀察者列表、不需要手動遍歷通知。語言層級的支援消除了大量樣板程式碼。
注意: 使用 event 時要注意記憶體洩漏問題——如果 Observer 註冊了 event 但忘記取消註冊(
-=),即使 Observer 已不再使用,它仍會被 Subject 的 event 持有參考而無法被垃圾回收。
本章小結#
OBSERVER 模式讓 Subject 與 Observer 之間保持鬆散耦合——Subject 不需要知道 Observer 的具體型別,只需透過介面(或 delegate)通知即可。C# 的 delegate/event 語法讓這個模式的實作變得極為自然與簡潔。